Annotation of gcc/config/i386/i386.c, revision 1.1.1.3

1.1.1.3 ! root        1: /* Subroutines for insn-output.c for Intel X86.
        !             2:    Copyright (C) 1988, 1992, 1994 Free Software Foundation, Inc.
1.1       root        3: 
                      4: This file is part of GNU CC.
                      5: 
                      6: GNU CC is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 2, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU CC is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU CC; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: #include <stdio.h>
                     21: #include <setjmp.h>
                     22: #include "config.h"
                     23: #include "rtl.h"
                     24: #include "regs.h"
                     25: #include "hard-reg-set.h"
                     26: #include "real.h"
                     27: #include "insn-config.h"
                     28: #include "conditions.h"
                     29: #include "insn-flags.h"
                     30: #include "output.h"
                     31: #include "insn-attr.h"
                     32: #include "tree.h"
                     33: #include "flags.h"
1.1.1.2   root       34: #include "function.h"
1.1       root       35: 
                     36: #ifdef EXTRA_CONSTRAINT
                     37: /* If EXTRA_CONSTRAINT is defined, then the 'S'
                     38:    constraint in REG_CLASS_FROM_LETTER will no longer work, and various
                     39:    asm statements that need 'S' for class SIREG will break.  */
                     40:  error EXTRA_CONSTRAINT conflicts with S constraint letter
                     41: /* The previous line used to be #error, but some compilers barf
                     42:    even if the conditional was untrue.  */
                     43: #endif
                     44: 
                     45: #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
                     46: 
                     47: extern FILE *asm_out_file;
                     48: extern char *strcat ();
                     49: 
                     50: char *singlemove_string ();
                     51: char *output_move_const_single ();
                     52: char *output_fp_cc0_set ();
                     53: 
                     54: char *hi_reg_name[] = HI_REGISTER_NAMES;
                     55: char *qi_reg_name[] = QI_REGISTER_NAMES;
                     56: char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
                     57: 
                     58: /* Array of the smallest class containing reg number REGNO, indexed by
                     59:    REGNO.  Used by REGNO_REG_CLASS in i386.h. */
                     60: 
                     61: enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
                     62: {
                     63:   /* ax, dx, cx, bx */
                     64:   AREG, DREG, CREG, BREG,
                     65:   /* si, di, bp, sp */
                     66:   SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
                     67:   /* FP registers */
                     68:   FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
                     69:   FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,       
                     70:   /* arg pointer */
                     71:   INDEX_REGS
                     72: };
                     73: 
                     74: /* Test and compare insns in i386.md store the information needed to
                     75:    generate branch and scc insns here.  */
                     76: 
1.1.1.3 ! root       77: struct rtx_def *i386_compare_op0 = NULL_RTX;
        !            78: struct rtx_def *i386_compare_op1 = NULL_RTX;
1.1       root       79: struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
1.1.1.3 ! root       80: 
        !            81: /* Register allocation order */
        !            82: char *i386_reg_alloc_order = (char *)0;
        !            83: static char regs_allocated[FIRST_PSEUDO_REGISTER];
        !            84: 
        !            85: 
        !            86: /* Sometimes certain combinations of command options do not make
        !            87:    sense on a particular target machine.  You can define a macro
        !            88:    `OVERRIDE_OPTIONS' to take account of this.  This macro, if
        !            89:    defined, is executed once just after all the command options have
        !            90:    been parsed.
        !            91: 
        !            92:    Don't use this macro to turn on various extra optimizations for
        !            93:    `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
        !            94: 
        !            95: void
        !            96: override_options ()
        !            97: {
        !            98:   int ch, i, regno;
        !            99: 
        !           100: #ifdef SUBTARGET_OVERRIDE_OPTIONS
        !           101:   SUBTARGET_OVERRIDE_OPTIONS;
        !           102: #endif
        !           103: 
        !           104:   /* Validate registers in register allocation order */
        !           105:   if (i386_reg_alloc_order)
        !           106:     {
        !           107:       for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
        !           108:        {
        !           109:          switch (ch)
        !           110:            {
        !           111:            case 'a':   regno = 0;      break;
        !           112:            case 'd':   regno = 1;      break;
        !           113:            case 'c':   regno = 2;      break;
        !           114:            case 'b':   regno = 3;      break;
        !           115:            case 'S':   regno = 4;      break;
        !           116:            case 'D':   regno = 5;      break;
        !           117:            case 'B':   regno = 6;      break;
        !           118: 
        !           119:            default:    fatal ("Register '%c' is unknown", ch);
        !           120:            }
        !           121: 
        !           122:          if (regs_allocated[regno])
        !           123:            fatal ("Register '%c' was already specified in the allocation order", ch);
        !           124: 
        !           125:          regs_allocated[regno] = 1;
        !           126:        }
        !           127:     }
        !           128: }
        !           129: 
        !           130: /* A C statement (sans semicolon) to choose the order in which to
        !           131:    allocate hard registers for pseudo-registers local to a basic
        !           132:    block.
        !           133: 
        !           134:    Store the desired register order in the array `reg_alloc_order'.
        !           135:    Element 0 should be the register to allocate first; element 1, the
        !           136:    next register; and so on.
        !           137: 
        !           138:    The macro body should not assume anything about the contents of
        !           139:    `reg_alloc_order' before execution of the macro.
        !           140: 
        !           141:    On most machines, it is not necessary to define this macro.  */
        !           142: 
        !           143: void
        !           144: order_regs_for_local_alloc ()
        !           145: {
        !           146:   int i, ch, order, regno;
        !           147: 
        !           148:   /* User specified the register allocation order */
        !           149:   if (i386_reg_alloc_order)
        !           150:     {
        !           151:       for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
        !           152:        {
        !           153:          switch (ch)
        !           154:            {
        !           155:            case 'a':   regno = 0;      break;
        !           156:            case 'd':   regno = 1;      break;
        !           157:            case 'c':   regno = 2;      break;
        !           158:            case 'b':   regno = 3;      break;
        !           159:            case 'S':   regno = 4;      break;
        !           160:            case 'D':   regno = 5;      break;
        !           161:            case 'B':   regno = 6;      break;
        !           162:            }
        !           163: 
        !           164:          reg_alloc_order[order++] = regno;
        !           165:        }
        !           166: 
        !           167:       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        !           168:        {
        !           169:          if (!regs_allocated[i])
        !           170:            reg_alloc_order[order++] = i;
        !           171:        }
        !           172:     }
        !           173: 
        !           174:   /* If users did not specify a register allocation order, favor eax
        !           175:      normally except if DImode variables are used, in which case
        !           176:      favor edx before eax, which seems to cause less spill register
        !           177:      not found messages.  */
        !           178:   else
        !           179:     {
        !           180:       rtx insn;
        !           181: 
        !           182:       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        !           183:        reg_alloc_order[i] = i;
        !           184: 
        !           185:       if (optimize)
        !           186:        {
        !           187:          int use_dca = FALSE;
        !           188: 
        !           189:          for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
        !           190:            {
        !           191:              if (GET_CODE (insn) == INSN)
        !           192:                {
        !           193:                  rtx set = NULL_RTX;
        !           194:                  rtx pattern = PATTERN (insn);
        !           195: 
        !           196:                  if (GET_CODE (pattern) == SET)
        !           197:                    set = pattern;
        !           198: 
        !           199:                  else if ((GET_CODE (pattern) == PARALLEL
        !           200:                            || GET_CODE (pattern) == SEQUENCE)
        !           201:                           && GET_CODE (XVECEXP (pattern, 0, 0)) == SET)
        !           202:                    set = XVECEXP (pattern, 0, 0);
        !           203: 
        !           204:                  if (set && GET_MODE (SET_SRC (set)) == DImode)
        !           205:                    {
        !           206:                      use_dca = TRUE;
        !           207:                      break;
        !           208:                    }
        !           209:                }
        !           210:            }
        !           211: 
        !           212:          if (use_dca)
        !           213:            {
        !           214:              reg_alloc_order[0] = 1;   /* edx */
        !           215:              reg_alloc_order[1] = 2;   /* ecx */
        !           216:              reg_alloc_order[2] = 0;   /* eax */
        !           217:            }
        !           218:        }
        !           219:     }
        !           220: }
        !           221: 
1.1       root      222: 
                    223: /* Output an insn whose source is a 386 integer register.  SRC is the
                    224:    rtx for the register, and TEMPLATE is the op-code template.  SRC may
                    225:    be either SImode or DImode.
                    226: 
                    227:    The template will be output with operands[0] as SRC, and operands[1]
                    228:    as a pointer to the top of the 386 stack.  So a call from floatsidf2
                    229:    would look like this:
                    230: 
                    231:       output_op_from_reg (operands[1], AS1 (fild%z0,%1));
                    232: 
                    233:    where %z0 corresponds to the caller's operands[1], and is used to
                    234:    emit the proper size suffix.
                    235: 
                    236:    ??? Extend this to handle HImode - a 387 can load and store HImode
                    237:    values directly. */
                    238: 
                    239: void
                    240: output_op_from_reg (src, template)
                    241:      rtx src;
                    242:      char *template;
                    243: {
                    244:   rtx xops[4];
1.1.1.2   root      245:   int size = GET_MODE_SIZE (GET_MODE (src));
1.1       root      246: 
                    247:   xops[0] = src;
                    248:   xops[1] = AT_SP (Pmode);
1.1.1.2   root      249:   xops[2] = GEN_INT (size);
1.1       root      250:   xops[3] = stack_pointer_rtx;
                    251: 
1.1.1.2   root      252:   if (size > UNITS_PER_WORD)
1.1       root      253:     {
1.1.1.2   root      254:       rtx high;
                    255:       if (size > 2 * UNITS_PER_WORD)
                    256:        {
                    257:          high = gen_rtx (REG, SImode, REGNO (src) + 2);
                    258:          output_asm_insn (AS1 (push%L0,%0), &high);
                    259:        }
                    260:       high = gen_rtx (REG, SImode, REGNO (src) + 1);
1.1       root      261:       output_asm_insn (AS1 (push%L0,%0), &high);
                    262:     }
                    263:   output_asm_insn (AS1 (push%L0,%0), &src);
                    264: 
                    265:   output_asm_insn (template, xops);
                    266: 
                    267:   output_asm_insn (AS2 (add%L3,%2,%3), xops);
                    268: }
                    269: 
                    270: /* Output an insn to pop an value from the 387 top-of-stack to 386
                    271:    register DEST. The 387 register stack is popped if DIES is true.  If
                    272:    the mode of DEST is an integer mode, a `fist' integer store is done,
                    273:    otherwise a `fst' float store is done. */
                    274: 
                    275: void
                    276: output_to_reg (dest, dies)
                    277:      rtx dest;
                    278:      int dies;
                    279: {
                    280:   rtx xops[4];
1.1.1.2   root      281:   int size = GET_MODE_SIZE (GET_MODE (dest));
1.1       root      282: 
                    283:   xops[0] = AT_SP (Pmode);
                    284:   xops[1] = stack_pointer_rtx;
1.1.1.2   root      285:   xops[2] = GEN_INT (size);
1.1       root      286:   xops[3] = dest;
                    287: 
                    288:   output_asm_insn (AS2 (sub%L1,%2,%1), xops);
                    289: 
                    290:   if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
                    291:     {
                    292:       if (dies)
                    293:        output_asm_insn (AS1 (fistp%z3,%y0), xops);
                    294:       else
                    295:        output_asm_insn (AS1 (fist%z3,%y0), xops);
                    296:     }
                    297:   else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)
                    298:     {
                    299:       if (dies)
                    300:        output_asm_insn (AS1 (fstp%z3,%y0), xops);
                    301:       else
1.1.1.2   root      302:        {
                    303:          if (GET_MODE (dest) == XFmode)
                    304:            {
                    305:              output_asm_insn (AS1 (fstp%z3,%y0), xops);
                    306:              output_asm_insn (AS1 (fld%z3,%y0), xops);
                    307:            }
                    308:          else
                    309:            output_asm_insn (AS1 (fst%z3,%y0), xops);
                    310:        }
1.1       root      311:     }
                    312:   else
                    313:     abort ();
                    314: 
                    315:   output_asm_insn (AS1 (pop%L0,%0), &dest);
                    316: 
1.1.1.2   root      317:   if (size > UNITS_PER_WORD)
1.1       root      318:     {
                    319:       dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
                    320:       output_asm_insn (AS1 (pop%L0,%0), &dest);
1.1.1.2   root      321:       if (size > 2 * UNITS_PER_WORD)
                    322:        {
                    323:          dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
                    324:          output_asm_insn (AS1 (pop%L0,%0), &dest);
                    325:        }
1.1       root      326:     }
                    327: }
                    328: 
                    329: char *
                    330: singlemove_string (operands)
                    331:      rtx *operands;
                    332: {
                    333:   rtx x;
                    334:   if (GET_CODE (operands[0]) == MEM
                    335:       && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
                    336:     {
                    337:       if (XEXP (x, 0) != stack_pointer_rtx)
                    338:        abort ();
                    339:       return "push%L1 %1";
                    340:     }
                    341:   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    342:     {
                    343:       return output_move_const_single (operands);
                    344:     }
                    345:   else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
                    346:     return AS2 (mov%L0,%1,%0);
                    347:   else if (CONSTANT_P (operands[1]))
                    348:     return AS2 (mov%L0,%1,%0);
                    349:   else
                    350:     {
                    351:       output_asm_insn ("push%L1 %1", operands);
                    352:       return "pop%L0 %0";
                    353:     }
                    354: }
                    355: 
                    356: /* Return a REG that occurs in ADDR with coefficient 1.
                    357:    ADDR can be effectively incremented by incrementing REG.  */
                    358: 
                    359: static rtx
                    360: find_addr_reg (addr)
                    361:      rtx addr;
                    362: {
                    363:   while (GET_CODE (addr) == PLUS)
                    364:     {
                    365:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    366:        addr = XEXP (addr, 0);
                    367:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                    368:        addr = XEXP (addr, 1);
                    369:       else if (CONSTANT_P (XEXP (addr, 0)))
                    370:        addr = XEXP (addr, 1);
                    371:       else if (CONSTANT_P (XEXP (addr, 1)))
                    372:        addr = XEXP (addr, 0);
                    373:       else
                    374:        abort ();
                    375:     }
                    376:   if (GET_CODE (addr) == REG)
                    377:     return addr;
                    378:   abort ();
                    379: }
                    380: 
1.1.1.3 ! root      381: 
1.1       root      382: /* Output an insn to add the constant N to the register X.  */
                    383: 
                    384: static void
                    385: asm_add (n, x)
                    386:      int n;
                    387:      rtx x;
                    388: {
                    389:   rtx xops[2];
1.1.1.3 ! root      390:   xops[0] = x;
        !           391: 
        !           392:   if (n == -1)
        !           393:     output_asm_insn (AS1 (dec%L0,%0), xops);
        !           394:   else if (n == 1)
        !           395:     output_asm_insn (AS1 (inc%L0,%0), xops);
        !           396:   else if (n < 0)
1.1       root      397:     {
1.1.1.3 ! root      398:       xops[1] = GEN_INT (-n);
        !           399:       output_asm_insn (AS2 (sub%L0,%1,%0), xops);
1.1       root      400:     }
                    401:   else if (n > 0)
                    402:     {
1.1.1.3 ! root      403:       xops[1] = GEN_INT (n);
        !           404:       output_asm_insn (AS2 (add%L0,%1,%0), xops);
1.1       root      405:     }
                    406: }
                    407: 
1.1.1.3 ! root      408: 
1.1       root      409: /* Output assembler code to perform a doubleword move insn
                    410:    with operands OPERANDS.  */
                    411: 
                    412: char *
                    413: output_move_double (operands)
                    414:      rtx *operands;
                    415: {
                    416:   enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    417:   rtx latehalf[2];
1.1.1.2   root      418:   rtx middlehalf[2];
                    419:   rtx xops[2];
1.1       root      420:   rtx addreg0 = 0, addreg1 = 0;
                    421:   int dest_overlapped_low = 0;
1.1.1.2   root      422:   int size = GET_MODE_SIZE (GET_MODE (operands[1]));
                    423: 
                    424:   middlehalf[0] = 0;
                    425:   middlehalf[1] = 0;
1.1       root      426: 
                    427:   /* First classify both operands.  */
                    428: 
                    429:   if (REG_P (operands[0]))
                    430:     optype0 = REGOP;
                    431:   else if (offsettable_memref_p (operands[0]))
                    432:     optype0 = OFFSOP;
                    433:   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
                    434:     optype0 = POPOP;
                    435:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
                    436:     optype0 = PUSHOP;
                    437:   else if (GET_CODE (operands[0]) == MEM)
                    438:     optype0 = MEMOP;
                    439:   else
                    440:     optype0 = RNDOP;
                    441: 
                    442:   if (REG_P (operands[1]))
                    443:     optype1 = REGOP;
                    444:   else if (CONSTANT_P (operands[1]))
                    445:     optype1 = CNSTOP;
                    446:   else if (offsettable_memref_p (operands[1]))
                    447:     optype1 = OFFSOP;
                    448:   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
                    449:     optype1 = POPOP;
                    450:   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
                    451:     optype1 = PUSHOP;
                    452:   else if (GET_CODE (operands[1]) == MEM)
                    453:     optype1 = MEMOP;
                    454:   else
                    455:     optype1 = RNDOP;
                    456: 
                    457:   /* Check for the cases that the operand constraints are not
                    458:      supposed to allow to happen.  Abort if we get one,
                    459:      because generating code for these cases is painful.  */
                    460: 
                    461:   if (optype0 == RNDOP || optype1 == RNDOP)
                    462:     abort ();
                    463: 
                    464:   /* If one operand is decrementing and one is incrementing
                    465:      decrement the former register explicitly
                    466:      and change that operand into ordinary indexing.  */
                    467: 
                    468:   if (optype0 == PUSHOP && optype1 == POPOP)
                    469:     {
1.1.1.2   root      470:       /* ??? Can this ever happen on i386? */
1.1       root      471:       operands[0] = XEXP (XEXP (operands[0], 0), 0);
1.1.1.2   root      472:       asm_add (-size, operands[0]);
                    473:       if (GET_MODE (operands[1]) == XFmode)
                    474:         operands[0] = gen_rtx (MEM, XFmode, operands[0]);
                    475:       else if (GET_MODE (operands[0]) == DFmode)
                    476:         operands[0] = gen_rtx (MEM, DFmode, operands[0]);
                    477:       else
                    478:         operands[0] = gen_rtx (MEM, DImode, operands[0]);
1.1       root      479:       optype0 = OFFSOP;
                    480:     }
1.1.1.2   root      481: 
1.1       root      482:   if (optype0 == POPOP && optype1 == PUSHOP)
                    483:     {
1.1.1.2   root      484:       /* ??? Can this ever happen on i386? */
1.1       root      485:       operands[1] = XEXP (XEXP (operands[1], 0), 0);
1.1.1.2   root      486:       asm_add (-size, operands[1]);
                    487:       if (GET_MODE (operands[1]) == XFmode)
                    488:         operands[1] = gen_rtx (MEM, XFmode, operands[1]);
                    489:       else if (GET_MODE (operands[1]) == DFmode)
                    490:         operands[1] = gen_rtx (MEM, DFmode, operands[1]);
                    491:       else
                    492:         operands[1] = gen_rtx (MEM, DImode, operands[1]);
1.1       root      493:       optype1 = OFFSOP;
                    494:     }
                    495: 
                    496:   /* If an operand is an unoffsettable memory ref, find a register
                    497:      we can increment temporarily to make it refer to the second word.  */
                    498: 
                    499:   if (optype0 == MEMOP)
                    500:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    501: 
                    502:   if (optype1 == MEMOP)
                    503:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    504: 
                    505:   /* Ok, we can do one word at a time.
                    506:      Normally we do the low-numbered word first,
                    507:      but if either operand is autodecrementing then we
                    508:      do the high-numbered word first.
                    509: 
                    510:      In either case, set up in LATEHALF the operands to use
                    511:      for the high-numbered word and in some cases alter the
                    512:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    513: 
1.1.1.2   root      514:   if (size == 12)
                    515:     {
                    516:       if (optype0 == REGOP)
                    517:        {
                    518:          middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    519:          latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
                    520:        }
                    521:       else if (optype0 == OFFSOP)
                    522:        {
                    523:          middlehalf[0] = adj_offsettable_operand (operands[0], 4);
                    524:          latehalf[0] = adj_offsettable_operand (operands[0], 8);
                    525:        }
                    526:       else
                    527:        {
                    528:          middlehalf[0] = operands[0];
                    529:          latehalf[0] = operands[0];
                    530:        }
                    531:     
                    532:       if (optype1 == REGOP)
                    533:        {
                    534:           middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    535:           latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
                    536:        }
                    537:       else if (optype1 == OFFSOP)
                    538:        {
                    539:           middlehalf[1] = adj_offsettable_operand (operands[1], 4);
                    540:           latehalf[1] = adj_offsettable_operand (operands[1], 8);
                    541:        }
                    542:       else if (optype1 == CNSTOP)
                    543:        {
                    544:          if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    545:            {
                    546:              REAL_VALUE_TYPE r; long l[3];
1.1       root      547: 
1.1.1.2   root      548:              REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
                    549:              REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
                    550:              operands[1] = GEN_INT (l[0]);
                    551:              middlehalf[1] = GEN_INT (l[1]);
                    552:              latehalf[1] = GEN_INT (l[2]);
                    553:            }
                    554:          else if (CONSTANT_P (operands[1]))
                    555:            /* No non-CONST_DOUBLE constant should ever appear here.  */
                    556:            abort ();
                    557:         }
                    558:       else
1.1       root      559:        {
1.1.1.2   root      560:          middlehalf[1] = operands[1];
                    561:          latehalf[1] = operands[1];
1.1       root      562:        }
                    563:     }
1.1.1.2   root      564:   else /* size is not 12: */
                    565:     {
                    566:       if (optype0 == REGOP)
                    567:        latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    568:       else if (optype0 == OFFSOP)
                    569:        latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    570:       else
                    571:        latehalf[0] = operands[0];
                    572: 
                    573:       if (optype1 == REGOP)
                    574:        latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    575:       else if (optype1 == OFFSOP)
                    576:        latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    577:       else if (optype1 == CNSTOP)
                    578:        {
                    579:          if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    580:            split_double (operands[1], &operands[1], &latehalf[1]);
                    581:          else if (CONSTANT_P (operands[1]))
                    582:            {
                    583:              /* ??? jrv: Can this really happen?  A DImode constant
                    584:                 that isn't a CONST_DOUBLE? */
                    585:              if (GET_CODE (operands[1]) == CONST_INT
                    586:                  && INTVAL (operands[1]) < 0)
                    587:                latehalf[1] = constm1_rtx;
                    588:              else
                    589:                latehalf[1] = const0_rtx;
                    590:            }
                    591:        }
                    592:       else
                    593:        latehalf[1] = operands[1];
                    594:     }
1.1       root      595: 
                    596:   /* If insn is effectively movd N (sp),-(sp) then we will do the
1.1.1.2   root      597:      high word first.  We should use the adjusted operand 1
                    598:      (which is N+4 (sp) or N+8 (sp))
                    599:      for the low word and middle word as well,
                    600:      to compensate for the first decrement of sp.  */
1.1       root      601:   if (optype0 == PUSHOP
                    602:       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
                    603:       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
1.1.1.2   root      604:     middlehalf[1] = operands[1] = latehalf[1];
1.1       root      605: 
                    606:   /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),
                    607:      if the upper part of reg N does not appear in the MEM, arrange to
                    608:      emit the move late-half first.  Otherwise, compute the MEM address
                    609:      into the upper part of N and use that as a pointer to the memory
                    610:      operand.  */
                    611:   if (optype0 == REGOP
                    612:       && (optype1 == OFFSOP || optype1 == MEMOP))
                    613:     {
                    614:       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
                    615:          && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
                    616:        {
                    617:          /* If both halves of dest are used in the src memory address,
                    618:             compute the address into latehalf of dest.  */
1.1.1.2   root      619: compadr:
1.1       root      620:          xops[0] = latehalf[0];
                    621:          xops[1] = XEXP (operands[1], 0);
                    622:          output_asm_insn (AS2 (lea%L0,%a1,%0), xops);
1.1.1.2   root      623:          if( GET_MODE (operands[1]) == XFmode )
                    624:            {
                    625: /*         abort (); */
                    626:              operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
                    627:              middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
                    628:              latehalf[1] = adj_offsettable_operand (operands[1], size-4);
                    629:            }
                    630:          else
                    631:            {
                    632:              operands[1] = gen_rtx (MEM, DImode, latehalf[0]);
                    633:              latehalf[1] = adj_offsettable_operand (operands[1], size-4);
                    634:            }
                    635:        }
                    636:       else if (size == 12
                    637:                 && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
                    638:        {
                    639:          /* Check for two regs used by both source and dest. */
                    640:          if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
                    641:                || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
                    642:                goto compadr;
                    643: 
                    644:          /* JRV says this can't happen: */
                    645:          if (addreg0 || addreg1)
                    646:              abort();
                    647: 
                    648:          /* Only the middle reg conflicts; simply put it last. */
                    649:          output_asm_insn (singlemove_string (operands), operands);
                    650:          output_asm_insn (singlemove_string (latehalf), latehalf);
                    651:          output_asm_insn (singlemove_string (middlehalf), middlehalf);
                    652:          return "";
1.1       root      653:        }
                    654:       else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
                    655:        /* If the low half of dest is mentioned in the source memory
                    656:           address, the arrange to emit the move late half first.  */
                    657:        dest_overlapped_low = 1;
                    658:     }
                    659: 
                    660:   /* If one or both operands autodecrementing,
                    661:      do the two words, high-numbered first.  */
                    662: 
                    663:   /* Likewise,  the first move would clobber the source of the second one,
                    664:      do them in the other order.  This happens only for registers;
                    665:      such overlap can't happen in memory unless the user explicitly
                    666:      sets it up, and that is an undefined circumstance.  */
                    667: 
1.1.1.2   root      668: /*
1.1       root      669:   if (optype0 == PUSHOP || optype1 == PUSHOP
                    670:       || (optype0 == REGOP && optype1 == REGOP
                    671:          && REGNO (operands[0]) == REGNO (latehalf[1]))
                    672:       || dest_overlapped_low)
1.1.1.2   root      673: */
                    674:   if (optype0 == PUSHOP || optype1 == PUSHOP
                    675:       || (optype0 == REGOP && optype1 == REGOP
                    676:          && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
                    677:              || REGNO (operands[0]) == REGNO (latehalf[1])))
                    678:       || dest_overlapped_low)
1.1       root      679:     {
                    680:       /* Make any unoffsettable addresses point at high-numbered word.  */
                    681:       if (addreg0)
1.1.1.2   root      682:        asm_add (size-4, addreg0);
1.1       root      683:       if (addreg1)
1.1.1.2   root      684:        asm_add (size-4, addreg1);
1.1       root      685: 
                    686:       /* Do that word.  */
                    687:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    688: 
                    689:       /* Undo the adds we just did.  */
                    690:       if (addreg0)
                    691:          asm_add (-4, addreg0);
                    692:       if (addreg1)
                    693:        asm_add (-4, addreg1);
                    694: 
1.1.1.2   root      695:       if (size == 12)
                    696:         {
                    697:         output_asm_insn (singlemove_string (middlehalf), middlehalf);
                    698:         if (addreg0)
                    699:            asm_add (-4, addreg0);
                    700:         if (addreg1)
                    701:           asm_add (-4, addreg1);
                    702:        }
                    703: 
1.1       root      704:       /* Do low-numbered word.  */
                    705:       return singlemove_string (operands);
                    706:     }
                    707: 
                    708:   /* Normal case: do the two words, low-numbered first.  */
                    709: 
                    710:   output_asm_insn (singlemove_string (operands), operands);
                    711: 
1.1.1.2   root      712:   /* Do the middle one of the three words for long double */
                    713:   if (size == 12)
                    714:     {
                    715:       if (addreg0)
                    716:         asm_add (4, addreg0);
                    717:       if (addreg1)
                    718:         asm_add (4, addreg1);
                    719: 
                    720:       output_asm_insn (singlemove_string (middlehalf), middlehalf);
                    721:     }
                    722: 
1.1       root      723:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    724:   if (addreg0)
                    725:     asm_add (4, addreg0);
                    726:   if (addreg1)
                    727:     asm_add (4, addreg1);
                    728: 
                    729:   /* Do that word.  */
                    730:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    731: 
                    732:   /* Undo the adds we just did.  */
                    733:   if (addreg0)
1.1.1.2   root      734:     asm_add (4-size, addreg0);
1.1       root      735:   if (addreg1)
1.1.1.2   root      736:     asm_add (4-size, addreg1);
1.1       root      737: 
                    738:   return "";
                    739: }
1.1.1.3 ! root      740: 
        !           741: 
        !           742: #define MAX_TMPS 2             /* max temporary registers used */
        !           743: 
        !           744: /* Output the appropriate code to move push memory on the stack */
        !           745: 
        !           746: char *
        !           747: output_move_pushmem (operands, insn, length, tmp_start, n_operands)
        !           748:      rtx operands[];
        !           749:      rtx insn;
        !           750:      int length;
        !           751:      int tmp_start;
        !           752:      int n_operands;
        !           753: {
        !           754: 
        !           755:   struct {
        !           756:     char *load;
        !           757:     char *push;
        !           758:     rtx   xops[2];
        !           759:   } tmp_info[MAX_TMPS];
        !           760: 
        !           761:   rtx src = operands[1];
        !           762:   int max_tmps = 0;
        !           763:   int offset = 0;
        !           764:   int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);
        !           765:   int stack_offset = 0;
        !           766:   int i, num_tmps;
        !           767:   rtx xops[1];
        !           768: 
        !           769:   if (!offsettable_memref_p (src))
        !           770:     fatal_insn ("Source is not offsettable", insn);
        !           771: 
        !           772:   if ((length & 3) != 0)
        !           773:     fatal_insn ("Pushing non-word aligned size", insn);
        !           774: 
        !           775:   /* Figure out which temporary registers we have available */
        !           776:   for (i = tmp_start; i < n_operands; i++)
        !           777:     {
        !           778:       if (GET_CODE (operands[i]) == REG)
        !           779:        {
        !           780:          if (reg_overlap_mentioned_p (operands[i], src))
        !           781:            continue;
        !           782: 
        !           783:          tmp_info[ max_tmps++ ].xops[1] = operands[i];
        !           784:          if (max_tmps == MAX_TMPS)
        !           785:            break;
        !           786:        }
        !           787:     }
        !           788: 
        !           789:   if (max_tmps == 0)
        !           790:     for (offset = length - 4; offset >= 0; offset -= 4)
        !           791:       {
        !           792:        xops[0] = adj_offsettable_operand (src, offset + stack_offset);
        !           793:        output_asm_insn (AS1(push%L0,%0), xops);
        !           794:        if (stack_p)
        !           795:          stack_offset += 4;
        !           796:       }
        !           797: 
        !           798:   else
        !           799:     for (offset = length - 4; offset >= 0; )
        !           800:       {
        !           801:        for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)
        !           802:          {
        !           803:            tmp_info[num_tmps].load    = AS2(mov%L0,%0,%1);
        !           804:            tmp_info[num_tmps].push    = AS1(push%L0,%1);
        !           805:            tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset);
        !           806:            offset -= 4;
        !           807:          }
        !           808: 
        !           809:        for (i = 0; i < num_tmps; i++)
        !           810:          output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
        !           811: 
        !           812:        for (i = 0; i < num_tmps; i++)
        !           813:          output_asm_insn (tmp_info[i].push, tmp_info[i].xops);
        !           814: 
        !           815:        if (stack_p)
        !           816:          stack_offset += 4*num_tmps;
        !           817:       }
        !           818: 
        !           819:   return "";
        !           820: }
        !           821: 
        !           822: 
        !           823: 
        !           824: /* Output the appropriate code to move data between two memory locations */
        !           825: 
        !           826: char *
        !           827: output_move_memory (operands, insn, length, tmp_start, n_operands)
        !           828:      rtx operands[];
        !           829:      rtx insn;
        !           830:      int length;
        !           831:      int tmp_start;
        !           832:      int n_operands;
        !           833: {
        !           834:   struct {
        !           835:     char *load;
        !           836:     char *store;
        !           837:     rtx   xops[3];
        !           838:   } tmp_info[MAX_TMPS];
        !           839: 
        !           840:   rtx dest = operands[0];
        !           841:   rtx src  = operands[1];
        !           842:   rtx qi_tmp = NULL_RTX;
        !           843:   int max_tmps = 0;
        !           844:   int offset = 0;
        !           845:   int i, num_tmps;
        !           846:   rtx xops[3];
        !           847: 
        !           848:   if (GET_CODE (dest) == MEM
        !           849:       && GET_CODE (XEXP (dest, 0)) == PRE_INC
        !           850:       && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
        !           851:     return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
        !           852: 
        !           853:   if (!offsettable_memref_p (src))
        !           854:     fatal_insn ("Source is not offsettable", insn);
        !           855: 
        !           856:   if (!offsettable_memref_p (dest))
        !           857:     fatal_insn ("Destination is not offsettable", insn);
        !           858: 
        !           859:   /* Figure out which temporary registers we have available */
        !           860:   for (i = tmp_start; i < n_operands; i++)
        !           861:     {
        !           862:       if (GET_CODE (operands[i]) == REG)
        !           863:        {
        !           864:          if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i]))
        !           865:            qi_tmp = operands[i];
        !           866: 
        !           867:          if (reg_overlap_mentioned_p (operands[i], dest))
        !           868:            fatal_insn ("Temporary register overlaps the destination", insn);
        !           869: 
        !           870:          if (reg_overlap_mentioned_p (operands[i], src))
        !           871:            fatal_insn ("Temporary register overlaps the source", insn);
        !           872: 
        !           873:          tmp_info[ max_tmps++ ].xops[2] = operands[i];
        !           874:          if (max_tmps == MAX_TMPS)
        !           875:            break;
        !           876:        }
        !           877:     }
        !           878: 
        !           879:   if (max_tmps == 0)
        !           880:     fatal_insn ("No scratch registers were found to do memory->memory moves", insn);
        !           881: 
        !           882:   if ((length & 1) != 0)
        !           883:     {
        !           884:       if (!qi_tmp)
        !           885:        fatal_insn ("No byte register found when moving odd # of bytes.", insn);
        !           886:     }
        !           887: 
        !           888:   while (length > 1)
        !           889:     {
        !           890:       for (num_tmps = 0; num_tmps < max_tmps; num_tmps++)
        !           891:        {
        !           892:          if (length >= 4)
        !           893:            {
        !           894:              tmp_info[num_tmps].load    = AS2(mov%L0,%1,%2);
        !           895:              tmp_info[num_tmps].store   = AS2(mov%L0,%2,%0);
        !           896:              tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
        !           897:              tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
        !           898:              offset += 4;
        !           899:              length -= 4;
        !           900:            }
        !           901:          else if (length >= 2)
        !           902:            {
        !           903:              tmp_info[num_tmps].load    = AS2(mov%W0,%1,%2);
        !           904:              tmp_info[num_tmps].store   = AS2(mov%W0,%2,%0);
        !           905:              tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
        !           906:              tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
        !           907:              offset += 2;
        !           908:              length -= 2;
        !           909:            }
        !           910:          else
        !           911:            break;
        !           912:        }
        !           913: 
        !           914:       for (i = 0; i < num_tmps; i++)
        !           915:        output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
        !           916: 
        !           917:       for (i = 0; i < num_tmps; i++)
        !           918:        output_asm_insn (tmp_info[i].store, tmp_info[i].xops);
        !           919:     }
        !           920: 
        !           921:   if (length == 1)
        !           922:     {
        !           923:       xops[0] = adj_offsettable_operand (dest, offset);
        !           924:       xops[1] = adj_offsettable_operand (src, offset);
        !           925:       xops[2] = qi_tmp;
        !           926:       output_asm_insn (AS2(mov%B0,%1,%2), xops);
        !           927:       output_asm_insn (AS2(mov%B0,%2,%0), xops);
        !           928:     }
        !           929: 
        !           930:   return "";
        !           931: }
        !           932: 
1.1       root      933: 
                    934: int
                    935: standard_80387_constant_p (x)
                    936:      rtx x;
                    937: {
                    938: #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
                    939:   REAL_VALUE_TYPE d;
                    940:   jmp_buf handler;
                    941:   int is0, is1;
                    942: 
                    943:   if (setjmp (handler))
                    944:     return 0;
                    945: 
                    946:   set_float_handler (handler);
                    947:   REAL_VALUE_FROM_CONST_DOUBLE (d, x);
                    948:   is0 = REAL_VALUES_EQUAL (d, dconst0);
                    949:   is1 = REAL_VALUES_EQUAL (d, dconst1);
                    950:   set_float_handler (NULL_PTR);
                    951: 
                    952:   if (is0)
                    953:     return 1;
                    954: 
                    955:   if (is1)
                    956:     return 2;
                    957: 
                    958:   /* Note that on the 80387, other constants, such as pi,
                    959:      are much slower to load as standard constants
                    960:      than to load from doubles in memory!  */
                    961: #endif
                    962: 
                    963:   return 0;
                    964: }
                    965: 
                    966: char *
                    967: output_move_const_single (operands)
                    968:      rtx *operands;
                    969: {
                    970:   if (FP_REG_P (operands[0]))
                    971:     {
                    972:       int conval = standard_80387_constant_p (operands[1]);
                    973: 
                    974:       if (conval == 1)
                    975:        return "fldz";
                    976: 
                    977:       if (conval == 2)
                    978:        return "fld1";
                    979:     }
                    980:   if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    981:     {
1.1.1.2   root      982:       REAL_VALUE_TYPE r; long l;
                    983: 
                    984:       if (GET_MODE (operands[1]) == XFmode)
                    985:        abort ();
                    986: 
                    987:       REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
                    988:       REAL_VALUE_TO_TARGET_SINGLE (r, l);
                    989:       operands[1] = GEN_INT (l);
1.1       root      990:     }
                    991:   return singlemove_string (operands);
                    992: }
                    993: 
                    994: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
                    995:    reference and a constant.  */
                    996: 
                    997: int
                    998: symbolic_operand (op, mode)
                    999:      register rtx op;
                   1000:      enum machine_mode mode;
                   1001: {
                   1002:   switch (GET_CODE (op))
                   1003:     {
                   1004:     case SYMBOL_REF:
                   1005:     case LABEL_REF:
                   1006:       return 1;
                   1007:     case CONST:
                   1008:       op = XEXP (op, 0);
                   1009:       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
                   1010:               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
                   1011:              && GET_CODE (XEXP (op, 1)) == CONST_INT);
                   1012:     default:
                   1013:       return 0;
                   1014:     }
                   1015: }
                   1016: 
                   1017: /* Test for a valid operand for a call instruction.
                   1018:    Don't allow the arg pointer register or virtual regs
                   1019:    since they may change into reg + const, which the patterns
                   1020:    can't handle yet.  */
                   1021: 
                   1022: int
                   1023: call_insn_operand (op, mode)
                   1024:      rtx op;
                   1025:      enum machine_mode mode;
                   1026: {
                   1027:   if (GET_CODE (op) == MEM
                   1028:       && ((CONSTANT_ADDRESS_P (XEXP (op, 0))
                   1029:           /* This makes a difference for PIC.  */
                   1030:           && general_operand (XEXP (op, 0), Pmode))
                   1031:          || (GET_CODE (XEXP (op, 0)) == REG
                   1032:              && XEXP (op, 0) != arg_pointer_rtx
                   1033:              && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
                   1034:                   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
                   1035:     return 1;
                   1036:   return 0;
                   1037: }
                   1038: 
                   1039: /* Like call_insn_operand but allow (mem (symbol_ref ...))
                   1040:    even if pic.  */
                   1041: 
                   1042: int
                   1043: expander_call_insn_operand (op, mode)
                   1044:      rtx op;
                   1045:      enum machine_mode mode;
                   1046: {
                   1047:   if (GET_CODE (op) == MEM
                   1048:       && (CONSTANT_ADDRESS_P (XEXP (op, 0))
                   1049:          || (GET_CODE (XEXP (op, 0)) == REG
                   1050:              && XEXP (op, 0) != arg_pointer_rtx
                   1051:              && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
                   1052:                   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
                   1053:     return 1;
                   1054:   return 0;
                   1055: }
                   1056: 
                   1057: /* Returns 1 if OP contains a symbol reference */
                   1058: 
                   1059: int
                   1060: symbolic_reference_mentioned_p (op)
                   1061:      rtx op;
                   1062: {
                   1063:   register char *fmt;
                   1064:   register int i;
                   1065: 
                   1066:   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
                   1067:     return 1;
                   1068: 
                   1069:   fmt = GET_RTX_FORMAT (GET_CODE (op));
                   1070:   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
                   1071:     {
                   1072:       if (fmt[i] == 'E')
                   1073:        {
                   1074:          register int j;
                   1075: 
                   1076:          for (j = XVECLEN (op, i) - 1; j >= 0; j--)
                   1077:            if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
                   1078:              return 1;
                   1079:        }
                   1080:       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
                   1081:        return 1;
                   1082:     }
                   1083: 
                   1084:   return 0;
                   1085: }
                   1086: 
                   1087: /* This function generates the assembly code for function entry.
                   1088:    FILE is an stdio stream to output the code to.
                   1089:    SIZE is an int: how many units of temporary storage to allocate. */
                   1090: 
                   1091: void
                   1092: function_prologue (file, size)
                   1093:      FILE *file;
                   1094:      int size;
                   1095: {
                   1096:   register int regno;
                   1097:   int limit;
                   1098:   rtx xops[4];
                   1099:   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
                   1100:                                  || current_function_uses_const_pool);
                   1101: 
                   1102:   xops[0] = stack_pointer_rtx;
                   1103:   xops[1] = frame_pointer_rtx;
                   1104:   xops[2] = GEN_INT (size);
                   1105:   if (frame_pointer_needed)
                   1106:     {
                   1107:       output_asm_insn ("push%L1 %1", xops);
                   1108:       output_asm_insn (AS2 (mov%L0,%0,%1), xops);
                   1109:     }
                   1110: 
                   1111:   if (size)
                   1112:     output_asm_insn (AS2 (sub%L0,%2,%0), xops);
                   1113: 
                   1114:   /* Note If use enter it is NOT reversed args.
                   1115:      This one is not reversed from intel!!
                   1116:      I think enter is slower.  Also sdb doesn't like it.
                   1117:      But if you want it the code is:
                   1118:      {
                   1119:      xops[3] = const0_rtx;
                   1120:      output_asm_insn ("enter %2,%3", xops);
                   1121:      }
                   1122:      */
                   1123:   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
                   1124:   for (regno = limit - 1; regno >= 0; regno--)
                   1125:     if ((regs_ever_live[regno] && ! call_used_regs[regno])
                   1126:        || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
                   1127:       {
                   1128:        xops[0] = gen_rtx (REG, SImode, regno);
                   1129:        output_asm_insn ("push%L0 %0", xops);
                   1130:       }
                   1131: 
                   1132:   if (pic_reg_used)
                   1133:     {
                   1134:       xops[0] = pic_offset_table_rtx;
                   1135:       xops[1] = (rtx) gen_label_rtx ();
                   1136: 
                   1137:       output_asm_insn (AS1 (call,%P1), xops);
                   1138:       ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1]));
                   1139:       output_asm_insn (AS1 (pop%L0,%0), xops);
                   1140:       output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
                   1141:     }
                   1142: }
                   1143: 
                   1144: /* Return 1 if it is appropriate to emit `ret' instructions in the
                   1145:    body of a function.  Do this only if the epilogue is simple, needing a
                   1146:    couple of insns.  Prior to reloading, we can't tell how many registers
                   1147:    must be saved, so return 0 then.
                   1148: 
                   1149:    If NON_SAVING_SETJMP is defined and true, then it is not possible
                   1150:    for the epilogue to be simple, so return 0.  This is a special case
                   1151:    since NON_SAVING_SETJMP will not cause regs_ever_live to change until
                   1152:    final, but jump_optimize may need to know sooner if a `return' is OK.  */
                   1153: 
                   1154: int
                   1155: simple_386_epilogue ()
                   1156: {
                   1157:   int regno;
                   1158:   int nregs = 0;
                   1159:   int reglimit = (frame_pointer_needed
                   1160:                  ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
                   1161:   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
                   1162:                                  || current_function_uses_const_pool);
                   1163: 
                   1164: #ifdef NON_SAVING_SETJMP
                   1165:   if (NON_SAVING_SETJMP && current_function_calls_setjmp)
                   1166:     return 0;
                   1167: #endif
                   1168: 
                   1169:   if (! reload_completed)
                   1170:     return 0;
                   1171: 
                   1172:   for (regno = reglimit - 1; regno >= 0; regno--)
                   1173:     if ((regs_ever_live[regno] && ! call_used_regs[regno])
                   1174:        || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
                   1175:       nregs++;
                   1176: 
                   1177:   return nregs == 0 || ! frame_pointer_needed;
                   1178: }
                   1179: 
1.1.1.3 ! root     1180: 
1.1       root     1181: /* This function generates the assembly code for function exit.
                   1182:    FILE is an stdio stream to output the code to.
                   1183:    SIZE is an int: how many units of temporary storage to deallocate. */
                   1184: 
                   1185: void
                   1186: function_epilogue (file, size)
                   1187:      FILE *file;
                   1188:      int size;
                   1189: {
                   1190:   register int regno;
                   1191:   register int nregs, limit;
                   1192:   int offset;
                   1193:   rtx xops[3];
                   1194:   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
                   1195:                                  || current_function_uses_const_pool);
                   1196: 
                   1197:   /* Compute the number of registers to pop */
                   1198: 
                   1199:   limit = (frame_pointer_needed
                   1200:           ? FRAME_POINTER_REGNUM
                   1201:           : STACK_POINTER_REGNUM);
                   1202: 
                   1203:   nregs = 0;
                   1204: 
                   1205:   for (regno = limit - 1; regno >= 0; regno--)
                   1206:     if ((regs_ever_live[regno] && ! call_used_regs[regno])
                   1207:        || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
                   1208:       nregs++;
                   1209: 
                   1210:   /* sp is often  unreliable so we must go off the frame pointer,
                   1211:    */
                   1212: 
                   1213:   /* In reality, we may not care if sp is unreliable, because we can
                   1214:      restore the register relative to the frame pointer.  In theory,
                   1215:      since each move is the same speed as a pop, and we don't need the
                   1216:      leal, this is faster.  For now restore multiple registers the old
                   1217:      way. */
                   1218: 
                   1219:   offset = -size - (nregs * UNITS_PER_WORD);
                   1220: 
                   1221:   xops[2] = stack_pointer_rtx;
                   1222: 
                   1223:   if (nregs > 1 || ! frame_pointer_needed)
                   1224:     {
                   1225:       if (frame_pointer_needed)
                   1226:        {
                   1227:          xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset);
                   1228:          output_asm_insn (AS2 (lea%L2,%0,%2), xops);
                   1229:        }
                   1230: 
                   1231:       for (regno = 0; regno < limit; regno++)
                   1232:        if ((regs_ever_live[regno] && ! call_used_regs[regno])
                   1233:            || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
                   1234:          {
                   1235:            xops[0] = gen_rtx (REG, SImode, regno);
                   1236:            output_asm_insn ("pop%L0 %0", xops);
                   1237:          }
                   1238:     }
                   1239:   else
                   1240:     for (regno = 0; regno < limit; regno++)
                   1241:       if ((regs_ever_live[regno] && ! call_used_regs[regno])
                   1242:          || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
                   1243:        {
                   1244:          xops[0] = gen_rtx (REG, SImode, regno);
                   1245:          xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
                   1246:          output_asm_insn (AS2 (mov%L0,%1,%0), xops);
                   1247:          offset += 4;
                   1248:        }
                   1249: 
                   1250:   if (frame_pointer_needed)
                   1251:     {
                   1252:       /* On i486, mov & pop is faster than "leave". */
                   1253: 
1.1.1.3 ! root     1254:       if (!TARGET_386)
1.1       root     1255:        {
                   1256:          xops[0] = frame_pointer_rtx;
                   1257:          output_asm_insn (AS2 (mov%L2,%0,%2), xops);
                   1258:          output_asm_insn ("pop%L0 %0", xops);
                   1259:        }
                   1260:       else
                   1261:        output_asm_insn ("leave", xops);
                   1262:     }
                   1263:   else if (size)
                   1264:     {
                   1265:       /* If there is no frame pointer, we must still release the frame. */
                   1266: 
                   1267:       xops[0] = GEN_INT (size);
                   1268:       output_asm_insn (AS2 (add%L2,%0,%2), xops);
                   1269:     }
                   1270: 
                   1271:   if (current_function_pops_args && current_function_args_size)
                   1272:     {
                   1273:       xops[1] = GEN_INT (current_function_pops_args);
                   1274: 
                   1275:       /* i386 can only pop 32K bytes (maybe 64K?  Is it signed?).  If
                   1276:         asked to pop more, pop return address, do explicit add, and jump
                   1277:         indirectly to the caller. */
                   1278: 
                   1279:       if (current_function_pops_args >= 32768)
                   1280:        {
                   1281:          /* ??? Which register to use here? */
                   1282:          xops[0] = gen_rtx (REG, SImode, 2);
                   1283:          output_asm_insn ("pop%L0 %0", xops);
                   1284:          output_asm_insn (AS2 (add%L2,%1,%2), xops);
                   1285:          output_asm_insn ("jmp %*%0", xops);
                   1286:        }
                   1287:       else
                   1288:          output_asm_insn ("ret %1", xops);
                   1289:     }
                   1290:   else
                   1291:     output_asm_insn ("ret", xops);
                   1292: }
1.1.1.3 ! root     1293: 
1.1       root     1294: 
1.1.1.3 ! root     1295: /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
        !          1296:    that is a valid memory address for an instruction.
        !          1297:    The MODE argument is the machine mode for the MEM expression
        !          1298:    that wants to use this address.
        !          1299: 
        !          1300:    On x86, legitimate addresses are:
        !          1301:        base                            movl (base),reg
        !          1302:        displacement                    movl disp,reg
        !          1303:        base + displacement             movl disp(base),reg
        !          1304:        index + base                    movl (base,index),reg
        !          1305:        (index + base) + displacement   movl disp(base,index),reg
        !          1306:        index*scale                     movl (,index,scale),reg
        !          1307:        index*scale + disp              movl disp(,index,scale),reg
        !          1308:        index*scale + base              movl (base,index,scale),reg
        !          1309:        (index*scale + base) + disp     movl disp(base,index,scale),reg
        !          1310: 
        !          1311:        In each case, scale can be 1, 2, 4, 8.  */
        !          1312: 
        !          1313: /* This is exactly the same as print_operand_addr, except that
        !          1314:    it recognizes addresses instead of printing them.
        !          1315: 
        !          1316:    It only recognizes address in canonical form.  LEGITIMIZE_ADDRESS should
        !          1317:    convert common non-canonical forms to canonical form so that they will
        !          1318:    be recognized.  */
        !          1319: 
        !          1320: #define ADDR_INVALID(msg,insn)                                         \
        !          1321: do {                                                                   \
        !          1322:   if (TARGET_DEBUG_ADDR)                                               \
        !          1323:     {                                                                  \
        !          1324:       fprintf (stderr, msg);                                           \
        !          1325:       debug_rtx (insn);                                                        \
        !          1326:     }                                                                  \
        !          1327: } while (0)
1.1       root     1328: 
1.1.1.3 ! root     1329: int
        !          1330: legitimate_address_p (mode, addr, strict)
        !          1331:      enum machine_mode mode;
        !          1332:      register rtx addr;
        !          1333:      int strict;
        !          1334: {
        !          1335:   rtx base  = NULL_RTX;
        !          1336:   rtx indx  = NULL_RTX;
        !          1337:   rtx scale = NULL_RTX;
        !          1338:   rtx disp  = NULL_RTX;
        !          1339: 
        !          1340:   if (TARGET_DEBUG_ADDR)
        !          1341:     {
        !          1342:       fprintf (stderr,
        !          1343:               "\n==========\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
        !          1344:               GET_MODE_NAME (mode), strict);
        !          1345: 
        !          1346:       debug_rtx (addr);
        !          1347:     }
        !          1348: 
        !          1349:   if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
        !          1350:       base = addr;                             /* base reg */
        !          1351: 
        !          1352:   else if (GET_CODE (addr) == PLUS)
        !          1353:     {
        !          1354:       rtx op0 = XEXP (addr, 0);
        !          1355:       rtx op1 = XEXP (addr, 1);
        !          1356:       enum rtx_code code0 = GET_CODE (op0);
        !          1357:       enum rtx_code code1 = GET_CODE (op1);
        !          1358: 
        !          1359:       if (code0 == REG || code0 == SUBREG)
        !          1360:        {
        !          1361:          if (code1 == REG || code1 == SUBREG)
        !          1362:            {
        !          1363:              indx = op0;                       /* index + base */
        !          1364:              base = op1;
        !          1365:            }
        !          1366: 
        !          1367:          else
        !          1368:            {
        !          1369:              base = op0;                       /* base + displacement */
        !          1370:              disp = op1;
        !          1371:            }
        !          1372:        }
        !          1373: 
        !          1374:       else if (code0 == MULT)
        !          1375:        {
        !          1376:          indx  = XEXP (op0, 0);
        !          1377:          scale = XEXP (op0, 1);
        !          1378: 
        !          1379:          if (code1 == REG || code1 == SUBREG)
        !          1380:            base = op1;                         /* index*scale + base */
        !          1381: 
        !          1382:          else
        !          1383:            disp = op1;                         /* index*scale + disp */
        !          1384:        }
        !          1385: 
        !          1386:       else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
        !          1387:        {
        !          1388:          indx  = XEXP (XEXP (op0, 0), 0);      /* index*scale + base + disp */
        !          1389:          scale = XEXP (XEXP (op0, 0), 1);
        !          1390:          base  = XEXP (op0, 1);
        !          1391:          disp  = op1;
        !          1392:        }
        !          1393: 
        !          1394:       else if (code0 == PLUS)
        !          1395:        {
        !          1396:          indx = XEXP (op0, 0);                 /* index + base + disp */
        !          1397:          base = XEXP (op0, 1);
        !          1398:          disp = op1;
        !          1399:        }
        !          1400: 
        !          1401:       else
        !          1402:        {
        !          1403:          ADDR_INVALID ("PLUS subcode is not valid.\n", op0);
        !          1404:          return FALSE;
        !          1405:        }
        !          1406:     }
        !          1407: 
        !          1408:   else if (GET_CODE (addr) == MULT)
        !          1409:     {
        !          1410:       indx  = XEXP (addr, 0);                  /* index*scale */
        !          1411:       scale = XEXP (addr, 1);
        !          1412:     }
        !          1413: 
        !          1414:   else
        !          1415:     disp = addr;                               /* displacement */
        !          1416: 
        !          1417:   /* Allow arg pointer and stack pointer as index if there is not scaling */
        !          1418:   if (base && indx && !scale
        !          1419:       && (indx == arg_pointer_rtx || indx == stack_pointer_rtx))
        !          1420:     {
        !          1421:       rtx tmp = base;
        !          1422:       base = indx;
        !          1423:       indx = tmp;
        !          1424:     }
        !          1425: 
        !          1426:   /* Validate base register */
        !          1427:   /* Don't allow SUBREG's here, it can lead to spill failures when the base
        !          1428:      is one word out of a two word structure, which is represented internally
        !          1429:      as a DImode int.  */
        !          1430:   if (base)
        !          1431:     {
        !          1432:       if (GET_CODE (base) != REG)
        !          1433:        {
        !          1434:          ADDR_INVALID ("Base is not a register.\n", base);
        !          1435:          return FALSE;
        !          1436:        }
        !          1437: 
        !          1438:       if ((strict && !REG_OK_FOR_BASE_STRICT_P (base))
        !          1439:          || (!strict && !REG_OK_FOR_BASE_NONSTRICT_P (base)))
        !          1440:        {
        !          1441:          ADDR_INVALID ("Base is not valid.\n", base);
        !          1442:          return FALSE;
        !          1443:        }
        !          1444:     }
        !          1445: 
        !          1446:   /* Validate index register */
        !          1447:   /* Don't allow SUBREG's here, it can lead to spill failures when the index
        !          1448:      is one word out of a two word structure, which is represented internally
        !          1449:      as a DImode int.  */
        !          1450:   if (indx)
        !          1451:     {
        !          1452:       if (GET_CODE (indx) != REG)
        !          1453:        {
        !          1454:          ADDR_INVALID ("Index is not a register.\n", indx);
        !          1455:          return FALSE;
        !          1456:        }
        !          1457: 
        !          1458:       if ((strict && !REG_OK_FOR_INDEX_STRICT_P (indx))
        !          1459:          || (!strict && !REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
        !          1460:        {
        !          1461:          ADDR_INVALID ("Index is not valid.\n", indx);
        !          1462:          return FALSE;
        !          1463:        }
        !          1464:     }
        !          1465:   else if (scale)
        !          1466:     abort ();                                  /* scale w/o index illegal */
        !          1467: 
        !          1468:   /* Validate scale factor */
        !          1469:   if (scale)
        !          1470:     {
        !          1471:       HOST_WIDE_INT value;
        !          1472: 
        !          1473:       if (GET_CODE (scale) != CONST_INT)
        !          1474:        {
        !          1475:          ADDR_INVALID ("Scale is not valid.\n", scale);
        !          1476:          return FALSE;
        !          1477:        }
        !          1478: 
        !          1479:       value = INTVAL (scale);
        !          1480:       if (value != 1 && value != 2 && value != 4 && value != 8)
        !          1481:        {
        !          1482:          ADDR_INVALID ("Scale is not a good multiplier.\n", scale);
        !          1483:          return FALSE;
        !          1484:        }
        !          1485:     }
        !          1486: 
        !          1487:   /* Validate displacement */
        !          1488:   if (disp)
        !          1489:     {
        !          1490:       if (!CONSTANT_ADDRESS_P (disp))
        !          1491:        {
        !          1492:          ADDR_INVALID ("Displacement is not valid.\n", disp);
        !          1493:          return FALSE;
        !          1494:        }
        !          1495: 
        !          1496:       if (GET_CODE (disp) == CONST_DOUBLE)
        !          1497:        {
        !          1498:          ADDR_INVALID ("Displacement is a const_double.\n", disp);
        !          1499:          return FALSE;
        !          1500:        }
        !          1501: 
        !          1502:       if (flag_pic && SYMBOLIC_CONST (disp) && base != pic_offset_table_rtx
        !          1503:          && (indx != pic_offset_table_rtx || scale != NULL_RTX))
        !          1504:        {
        !          1505:          ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp);
        !          1506:          return FALSE;
        !          1507:        }
        !          1508: 
        !          1509:       if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
        !          1510:          && (base != NULL_RTX || indx != NULL_RTX))
        !          1511:        {
        !          1512:          ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", disp);
        !          1513:          return FALSE;
        !          1514:        }
        !          1515:     }
        !          1516: 
        !          1517:   if (TARGET_DEBUG_ADDR)
        !          1518:     fprintf (stderr, "Address is valid.\n");
        !          1519: 
        !          1520:   /* Everything looks valid, return true */
        !          1521:   return TRUE;
        !          1522: }
        !          1523: 
        !          1524: 
        !          1525: /* Return a legitimate reference for ORIG (an address) using the
        !          1526:    register REG.  If REG is 0, a new pseudo is generated.
        !          1527: 
        !          1528:    There are three types of references that must be handled:
        !          1529: 
        !          1530:    1. Global data references must load the address from the GOT, via
        !          1531:       the PIC reg.  An insn is emitted to do this load, and the reg is
        !          1532:       returned.
        !          1533: 
        !          1534:    2. Static data references must compute the address as an offset
        !          1535:       from the GOT, whose base is in the PIC reg.  An insn is emitted to
        !          1536:       compute the address into a reg, and the reg is returned.  Static
        !          1537:       data objects have SYMBOL_REF_FLAG set to differentiate them from
        !          1538:       global data objects.
        !          1539: 
        !          1540:    3. Constant pool addresses must be handled special.  They are
        !          1541:       considered legitimate addresses, but only if not used with regs.
        !          1542:       When printed, the output routines know to print the reference with the
        !          1543:       PIC reg, even though the PIC reg doesn't appear in the RTL.
        !          1544: 
        !          1545:    GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
        !          1546:    reg also appears in the address (except for constant pool references,
        !          1547:    noted above).
        !          1548: 
        !          1549:    "switch" statements also require special handling when generating
        !          1550:    PIC code.  See comments by the `casesi' insn in i386.md for details.  */
        !          1551: 
        !          1552: rtx
        !          1553: legitimize_pic_address (orig, reg)
        !          1554:      rtx orig;
        !          1555:      rtx reg;
        !          1556: {
        !          1557:   rtx addr = orig;
        !          1558:   rtx new = orig;
        !          1559: 
        !          1560:   if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
        !          1561:     {
        !          1562:       if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
        !          1563:        reg = new = orig;
        !          1564:       else
        !          1565:        {
        !          1566:          if (reg == 0)
        !          1567:            reg = gen_reg_rtx (Pmode);
        !          1568: 
        !          1569:          if ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
        !          1570:              || GET_CODE (addr) == LABEL_REF)
        !          1571:            new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
        !          1572:          else
        !          1573:            new = gen_rtx (MEM, Pmode,
        !          1574:                           gen_rtx (PLUS, Pmode,
        !          1575:                                    pic_offset_table_rtx, orig));
        !          1576: 
        !          1577:          emit_move_insn (reg, new);
        !          1578:        }
        !          1579:       current_function_uses_pic_offset_table = 1;
        !          1580:       return reg;
        !          1581:     }
        !          1582:   else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
        !          1583:     {
        !          1584:       rtx base;
        !          1585: 
        !          1586:       if (GET_CODE (addr) == CONST)
        !          1587:        {
        !          1588:          addr = XEXP (addr, 0);
        !          1589:          if (GET_CODE (addr) != PLUS)
        !          1590:            abort ();
        !          1591:        }
        !          1592: 
        !          1593:       if (XEXP (addr, 0) == pic_offset_table_rtx)
        !          1594:        return orig;
        !          1595: 
        !          1596:       if (reg == 0)
        !          1597:        reg = gen_reg_rtx (Pmode);
        !          1598: 
        !          1599:       base = legitimize_pic_address (XEXP (addr, 0), reg);
        !          1600:       addr = legitimize_pic_address (XEXP (addr, 1),
        !          1601:                                     base == reg ? NULL_RTX : reg);
        !          1602: 
        !          1603:       if (GET_CODE (addr) == CONST_INT)
        !          1604:        return plus_constant (base, INTVAL (addr));
        !          1605: 
        !          1606:       if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
        !          1607:        {
        !          1608:          base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
        !          1609:          addr = XEXP (addr, 1);
        !          1610:        }
        !          1611:        return gen_rtx (PLUS, Pmode, base, addr);
        !          1612:     }
        !          1613:   return new;
        !          1614: }
        !          1615: 
        !          1616: 
        !          1617: /* Emit insns to move operands[1] into operands[0].  */
        !          1618: 
        !          1619: void
        !          1620: emit_pic_move (operands, mode)
        !          1621:      rtx *operands;
        !          1622:      enum machine_mode mode;
        !          1623: {
        !          1624:   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
        !          1625: 
        !          1626:   if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
        !          1627:     operands[1] = (rtx) force_reg (SImode, operands[1]);
        !          1628:   else
        !          1629:     operands[1] = legitimize_pic_address (operands[1], temp);
        !          1630: }
        !          1631: 
        !          1632: 
        !          1633: /* Try machine-dependent ways of modifying an illegitimate address
        !          1634:    to be legitimate.  If we find one, return the new, valid address.
        !          1635:    This macro is used in only one place: `memory_address' in explow.c.
        !          1636: 
        !          1637:    OLDX is the address as it was before break_out_memory_refs was called.
        !          1638:    In some cases it is useful to look at this to decide what needs to be done.
        !          1639: 
        !          1640:    MODE and WIN are passed so that this macro can use
        !          1641:    GO_IF_LEGITIMATE_ADDRESS.
        !          1642: 
        !          1643:    It is always safe for this macro to do nothing.  It exists to recognize
        !          1644:    opportunities to optimize the output.
        !          1645: 
        !          1646:    For the 80386, we handle X+REG by loading X into a register R and
        !          1647:    using R+REG.  R will go in a general reg and indexing will be used.
        !          1648:    However, if REG is a broken-out memory address or multiplication,
        !          1649:    nothing needs to be done because REG can certainly go in a general reg.
        !          1650: 
        !          1651:    When -fpic is used, special handling is needed for symbolic references.
        !          1652:    See comments by legitimize_pic_address in i386.c for details.  */
        !          1653: 
        !          1654: rtx
        !          1655: legitimize_address (x, oldx, mode)
        !          1656:      register rtx x;
        !          1657:      register rtx oldx;
        !          1658:      enum machine_mode mode;
        !          1659: {
        !          1660:   int changed = 0;
        !          1661:   unsigned log;
        !          1662: 
        !          1663:   if (TARGET_DEBUG_ADDR)
        !          1664:     {
        !          1665:       fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", GET_MODE_NAME (mode));
        !          1666:       debug_rtx (x);
        !          1667:     }
        !          1668: 
        !          1669:   if (flag_pic && SYMBOLIC_CONST (x))
        !          1670:     return legitimize_pic_address (x, 0);
        !          1671: 
        !          1672:   /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
        !          1673:   if (GET_CODE (x) == ASHIFT
        !          1674:       && GET_CODE (XEXP (x, 1)) == CONST_INT
        !          1675:       && (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4)
        !          1676:     {
        !          1677:       changed = 1;
        !          1678:       x = gen_rtx (MULT, Pmode,
        !          1679:                   force_reg (Pmode, XEXP (x, 0)),
        !          1680:                   GEN_INT (1 << log));
        !          1681:     }
        !          1682: 
        !          1683:   if (GET_CODE (x) == PLUS)
        !          1684:     {
        !          1685:       /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
        !          1686:       if (GET_CODE (XEXP (x, 0)) == ASHIFT
        !          1687:          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
        !          1688:          && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4)
        !          1689:        {
        !          1690:          changed = 1;
        !          1691:          XEXP (x, 0) = gen_rtx (MULT, Pmode,
        !          1692:                                 force_reg (Pmode, XEXP (XEXP (x, 0), 0)),
        !          1693:                                 GEN_INT (1 << log));
        !          1694:        }
        !          1695: 
        !          1696:       if (GET_CODE (XEXP (x, 1)) == ASHIFT
        !          1697:          && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
        !          1698:          && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4)
        !          1699:        {
        !          1700:          changed = 1;
        !          1701:          XEXP (x, 1) = gen_rtx (MULT, Pmode,
        !          1702:                                 force_reg (Pmode, XEXP (XEXP (x, 1), 0)),
        !          1703:                                 GEN_INT (1 << log));
        !          1704:        }
        !          1705: 
        !          1706:       /* Put multiply first if it isn't already */
        !          1707:       if (GET_CODE (XEXP (x, 1)) == MULT)
        !          1708:        {
        !          1709:          rtx tmp = XEXP (x, 0);
        !          1710:          XEXP (x, 0) = XEXP (x, 1);
        !          1711:          XEXP (x, 1) = tmp;
        !          1712:          changed = 1;
        !          1713:        }
        !          1714: 
        !          1715:       /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const)))
        !          1716:         into (plus (plus (mult (reg) (const)) (reg)) (const)).  This can be
        !          1717:         created by virtual register instantiation, register elimination, and
        !          1718:         similar optimizations.  */
        !          1719:       if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS)
        !          1720:        {
        !          1721:          changed = 1;
        !          1722:          x = gen_rtx (PLUS, Pmode,
        !          1723:                       gen_rtx (PLUS, Pmode, XEXP (x, 0), XEXP (XEXP (x, 1), 0)),
        !          1724:                       XEXP (XEXP (x, 1), 1));
        !          1725:        }
        !          1726: 
        !          1727:       /* Canonicalize (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
        !          1728:         into (plus (plus (mult (reg) (const)) (reg)) (const)).  */
        !          1729:       else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS
        !          1730:               && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
        !          1731:               && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS
        !          1732:               && CONSTANT_P (XEXP (x, 1)))
        !          1733:        {
        !          1734:          rtx constant, other;
        !          1735: 
        !          1736:          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
        !          1737:            {
        !          1738:              constant = XEXP (x, 1);
        !          1739:              other = XEXP (XEXP (XEXP (x, 0), 1), 1);
        !          1740:            }
        !          1741:          else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT)
        !          1742:            {
        !          1743:              constant = XEXP (XEXP (XEXP (x, 0), 1), 1);
        !          1744:              other = XEXP (x, 1);
        !          1745:            }
        !          1746:          else
        !          1747:            constant = 0;
        !          1748: 
        !          1749:          if (constant)
        !          1750:            {
        !          1751:              changed = 1;
        !          1752:              x = gen_rtx (PLUS, Pmode,
        !          1753:                           gen_rtx (PLUS, Pmode, XEXP (XEXP (x, 0), 0),
        !          1754:                                    XEXP (XEXP (XEXP (x, 0), 1), 0)),
        !          1755:                           plus_constant (other, INTVAL (constant)));
        !          1756:            }
        !          1757:        }
        !          1758: 
        !          1759:       if (changed && legitimate_address_p (mode, x, FALSE))
        !          1760:        return x;
        !          1761: 
        !          1762:       if (GET_CODE (XEXP (x, 0)) == MULT)
        !          1763:        {
        !          1764:          changed = 1;
        !          1765:          XEXP (x, 0) = force_operand (XEXP (x, 0), 0);
        !          1766:        }
        !          1767: 
        !          1768:       if (GET_CODE (XEXP (x, 1)) == MULT)
        !          1769:        {
        !          1770:          changed = 1;
        !          1771:          XEXP (x, 1) = force_operand (XEXP (x, 1), 0);
        !          1772:        }
        !          1773: 
        !          1774:       if (changed
        !          1775:          && GET_CODE (XEXP (x, 1)) == REG
        !          1776:          && GET_CODE (XEXP (x, 0)) == REG)
        !          1777:        return x;
        !          1778: 
        !          1779:       if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1)))
        !          1780:        {
        !          1781:          changed = 1;
        !          1782:          x = legitimize_pic_address (x, 0);
        !          1783:        }
        !          1784: 
        !          1785:       if (changed && legitimate_address_p (mode, x, FALSE))
        !          1786:        return x;
        !          1787: 
        !          1788:       if (GET_CODE (XEXP (x, 0)) == REG)
        !          1789:        {
        !          1790:          register rtx temp = gen_reg_rtx (Pmode);
        !          1791:          register rtx val  = force_operand (XEXP (x, 1), temp);
        !          1792:          if (val != temp)
        !          1793:            emit_move_insn (temp, val);
        !          1794: 
        !          1795:          XEXP (x, 1) = temp;
        !          1796:          return x;
        !          1797:        }
        !          1798: 
        !          1799:       else if (GET_CODE (XEXP (x, 1)) == REG)
        !          1800:        {
        !          1801:          register rtx temp = gen_reg_rtx (Pmode);
        !          1802:          register rtx val  = force_operand (XEXP (x, 0), temp);
        !          1803:          if (val != temp)
        !          1804:            emit_move_insn (temp, val);
        !          1805: 
        !          1806:          XEXP (x, 0) = temp;
        !          1807:          return x;
        !          1808:        }
        !          1809:     }
        !          1810: 
        !          1811:   return x;
        !          1812: }
        !          1813: 
        !          1814: 
        !          1815: /* Print an integer constant expression in assembler syntax.  Addition
        !          1816:    and subtraction are the only arithmetic that may appear in these
        !          1817:    expressions.  FILE is the stdio stream to write to, X is the rtx, and
        !          1818:    CODE is the operand print code from the output string.  */
        !          1819: 
        !          1820: static void
        !          1821: output_pic_addr_const (file, x, code)
        !          1822:      FILE *file;
        !          1823:      rtx x;
        !          1824:      int code;
        !          1825: {
        !          1826:   char buf[256];
1.1       root     1827: 
                   1828:   switch (GET_CODE (x))
                   1829:     {
                   1830:     case PC:
                   1831:       if (flag_pic)
                   1832:        putc ('.', file);
                   1833:       else
                   1834:        abort ();
                   1835:       break;
                   1836: 
                   1837:     case SYMBOL_REF:
                   1838:     case LABEL_REF:
                   1839:       if (GET_CODE (x) == SYMBOL_REF)
                   1840:        assemble_name (file, XSTR (x, 0));
                   1841:       else
                   1842:        {
                   1843:          ASM_GENERATE_INTERNAL_LABEL (buf, "L",
                   1844:                                       CODE_LABEL_NUMBER (XEXP (x, 0)));
                   1845:          assemble_name (asm_out_file, buf);
                   1846:        }
                   1847: 
                   1848:       if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
                   1849:        fprintf (file, "@GOTOFF(%%ebx)");
                   1850:       else if (code == 'P')
                   1851:        fprintf (file, "@PLT");
1.1.1.3 ! root     1852:       else if (GET_CODE (x) == LABEL_REF)
        !          1853:        fprintf (file, "@GOTOFF");
        !          1854:       else if (! SYMBOL_REF_FLAG (x))
1.1       root     1855:        fprintf (file, "@GOT");
                   1856:       else
                   1857:        fprintf (file, "@GOTOFF");
                   1858: 
                   1859:       break;
                   1860: 
                   1861:     case CODE_LABEL:
                   1862:       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
                   1863:       assemble_name (asm_out_file, buf);
                   1864:       break;
                   1865: 
                   1866:     case CONST_INT:
                   1867:       fprintf (file, "%d", INTVAL (x));
                   1868:       break;
                   1869: 
                   1870:     case CONST:
                   1871:       /* This used to output parentheses around the expression,
                   1872:         but that does not work on the 386 (either ATT or BSD assembler).  */
                   1873:       output_pic_addr_const (file, XEXP (x, 0), code);
                   1874:       break;
                   1875: 
                   1876:     case CONST_DOUBLE:
                   1877:       if (GET_MODE (x) == VOIDmode)
                   1878:        {
                   1879:          /* We can use %d if the number is <32 bits and positive.  */
                   1880:          if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
                   1881:            fprintf (file, "0x%x%08x",
                   1882:                     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
                   1883:          else
                   1884:            fprintf (file, "%d", CONST_DOUBLE_LOW (x));
                   1885:        }
                   1886:       else
                   1887:        /* We can't handle floating point constants;
                   1888:           PRINT_OPERAND must handle them.  */
                   1889:        output_operand_lossage ("floating constant misused");
                   1890:       break;
                   1891: 
                   1892:     case PLUS:
                   1893:       /* Some assemblers need integer constants to appear last (eg masm).  */
                   1894:       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
                   1895:        {
                   1896:          output_pic_addr_const (file, XEXP (x, 1), code);
                   1897:          if (INTVAL (XEXP (x, 0)) >= 0)
                   1898:            fprintf (file, "+");
                   1899:          output_pic_addr_const (file, XEXP (x, 0), code);
                   1900:        }
                   1901:       else
                   1902:        {
                   1903:          output_pic_addr_const (file, XEXP (x, 0), code);
                   1904:          if (INTVAL (XEXP (x, 1)) >= 0)
                   1905:            fprintf (file, "+");
                   1906:          output_pic_addr_const (file, XEXP (x, 1), code);
                   1907:        }
                   1908:       break;
                   1909: 
                   1910:     case MINUS:
                   1911:       output_pic_addr_const (file, XEXP (x, 0), code);
                   1912:       fprintf (file, "-");
                   1913:       output_pic_addr_const (file, XEXP (x, 1), code);
                   1914:       break;
                   1915: 
                   1916:     default:
                   1917:       output_operand_lossage ("invalid expression as operand");
                   1918:     }
                   1919: }
                   1920: 
                   1921: /* Meaning of CODE:
                   1922:    f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
                   1923:    D,L,W,B,Q,S -- print the opcode suffix for specified size of operand.
                   1924:    R -- print the prefix for register names.
                   1925:    z -- print the opcode suffix for the size of the current operand.
                   1926:    * -- print a star (in certain assembler syntax)
                   1927:    w -- print the operand as if it's a "word" (HImode) even if it isn't.
                   1928:    c -- don't print special prefixes before constant operands.
                   1929: */
                   1930: 
                   1931: void
                   1932: print_operand (file, x, code)
                   1933:      FILE *file;
                   1934:      rtx x;
                   1935:      int code;
                   1936: {
                   1937:   if (code)
                   1938:     {
                   1939:       switch (code)
                   1940:        {
                   1941:        case '*':
                   1942:          if (USE_STAR)
                   1943:            putc ('*', file);
                   1944:          return;
                   1945: 
                   1946:        case 'L':
                   1947:          PUT_OP_SIZE (code, 'l', file);
                   1948:          return;
                   1949: 
                   1950:        case 'W':
                   1951:          PUT_OP_SIZE (code, 'w', file);
                   1952:          return;
                   1953: 
                   1954:        case 'B':
                   1955:          PUT_OP_SIZE (code, 'b', file);
                   1956:          return;
                   1957: 
                   1958:        case 'Q':
                   1959:          PUT_OP_SIZE (code, 'l', file);
                   1960:          return;
                   1961: 
                   1962:        case 'S':
                   1963:          PUT_OP_SIZE (code, 's', file);
                   1964:          return;
                   1965: 
1.1.1.2   root     1966:        case 'T':
                   1967:          PUT_OP_SIZE (code, 't', file);
                   1968:          return;
                   1969: 
1.1       root     1970:        case 'z':
                   1971:          /* 387 opcodes don't get size suffixes if the operands are
                   1972:             registers. */
                   1973: 
                   1974:          if (STACK_REG_P (x))
                   1975:            return;
                   1976: 
                   1977:          /* this is the size of op from size of operand */
                   1978:          switch (GET_MODE_SIZE (GET_MODE (x)))
                   1979:            {
                   1980:            case 1:
                   1981:              PUT_OP_SIZE ('B', 'b', file);
                   1982:              return;
                   1983: 
                   1984:            case 2:
                   1985:              PUT_OP_SIZE ('W', 'w', file);
                   1986:              return;
                   1987: 
                   1988:            case 4:
                   1989:              if (GET_MODE (x) == SFmode)
                   1990:                {
                   1991:                  PUT_OP_SIZE ('S', 's', file);
                   1992:                  return;
                   1993:                }
                   1994:              else
                   1995:                PUT_OP_SIZE ('L', 'l', file);
                   1996:              return;
                   1997: 
1.1.1.2   root     1998:            case 12:
                   1999:                  PUT_OP_SIZE ('T', 't', file);
                   2000:                  return;
                   2001: 
1.1       root     2002:            case 8:
                   2003:              if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
                   2004:                {
                   2005: #ifdef GAS_MNEMONICS
                   2006:                  PUT_OP_SIZE ('Q', 'q', file);
                   2007:                  return;
                   2008: #else
                   2009:                  PUT_OP_SIZE ('Q', 'l', file); /* Fall through */
                   2010: #endif
                   2011:                }
                   2012: 
                   2013:              PUT_OP_SIZE ('Q', 'l', file);
                   2014:              return;
                   2015:            }
                   2016: 
                   2017:        case 'b':
                   2018:        case 'w':
                   2019:        case 'k':
                   2020:        case 'h':
                   2021:        case 'y':
                   2022:        case 'P':
                   2023:          break;
                   2024: 
                   2025:        default:
                   2026:          {
                   2027:            char str[50];
                   2028: 
                   2029:            sprintf (str, "invalid operand code `%c'", code);
                   2030:            output_operand_lossage (str);
                   2031:          }
                   2032:        }
                   2033:     }
                   2034:   if (GET_CODE (x) == REG)
                   2035:     {
                   2036:       PRINT_REG (x, code, file);
                   2037:     }
                   2038:   else if (GET_CODE (x) == MEM)
                   2039:     {
                   2040:       PRINT_PTR (x, file);
                   2041:       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
                   2042:        {
                   2043:          if (flag_pic)
                   2044:            output_pic_addr_const (file, XEXP (x, 0), code);
                   2045:          else
                   2046:            output_addr_const (file, XEXP (x, 0));
                   2047:        }
                   2048:       else
                   2049:        output_address (XEXP (x, 0));
                   2050:     }
                   2051:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
                   2052:     {
1.1.1.2   root     2053:       REAL_VALUE_TYPE r; long l;
                   2054:       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                   2055:       REAL_VALUE_TO_TARGET_SINGLE (r, l);
1.1       root     2056:       PRINT_IMMED_PREFIX (file);
1.1.1.2   root     2057:       fprintf (file, "0x%x", l);
1.1       root     2058:     }
1.1.1.2   root     2059:  /* These float cases don't actually occur as immediate operands. */
                   2060:  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
1.1       root     2061:     {
1.1.1.2   root     2062:       REAL_VALUE_TYPE r; char dstr[30];
                   2063:       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                   2064:       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
                   2065:       fprintf (file, "%s", dstr);
                   2066:     }
                   2067:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode)
                   2068:     {
                   2069:       REAL_VALUE_TYPE r; char dstr[30];
                   2070:       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                   2071:       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
                   2072:       fprintf (file, "%s", dstr);
1.1       root     2073:     }
                   2074:   else 
                   2075:     {
                   2076:       if (code != 'P')
                   2077:        {
                   2078:          if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
                   2079:            PRINT_IMMED_PREFIX (file);
                   2080:          else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF
                   2081:                   || GET_CODE (x) == LABEL_REF)
                   2082:            PRINT_OFFSET_PREFIX (file);
                   2083:        }
                   2084:       if (flag_pic)
                   2085:        output_pic_addr_const (file, x, code);
                   2086:       else
                   2087:        output_addr_const (file, x);
                   2088:     }
                   2089: }
                   2090: 
                   2091: /* Print a memory operand whose address is ADDR.  */
                   2092: 
                   2093: void
                   2094: print_operand_address (file, addr)
                   2095:      FILE *file;
                   2096:      register rtx addr;
                   2097: {
                   2098:   register rtx reg1, reg2, breg, ireg;
                   2099:   rtx offset;
                   2100: 
                   2101:   switch (GET_CODE (addr))
                   2102:     {
                   2103:     case REG:
                   2104:       ADDR_BEG (file);
                   2105:       fprintf (file, "%se", RP);
                   2106:       fputs (hi_reg_name[REGNO (addr)], file);
                   2107:       ADDR_END (file);
                   2108:       break;
                   2109: 
                   2110:     case PLUS:
                   2111:       reg1 = 0;
                   2112:       reg2 = 0;
                   2113:       ireg = 0;
                   2114:       breg = 0;
                   2115:       offset = 0;
                   2116:       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
                   2117:        {
                   2118:          offset = XEXP (addr, 0);
                   2119:          addr = XEXP (addr, 1);
                   2120:        }
                   2121:       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
                   2122:        {
                   2123:          offset = XEXP (addr, 1);
                   2124:          addr = XEXP (addr, 0);
                   2125:        }
                   2126:       if (GET_CODE (addr) != PLUS) ;
                   2127:       else if (GET_CODE (XEXP (addr, 0)) == MULT)
                   2128:        {
                   2129:          reg1 = XEXP (addr, 0);
                   2130:          addr = XEXP (addr, 1);
                   2131:        }
                   2132:       else if (GET_CODE (XEXP (addr, 1)) == MULT)
                   2133:        {
                   2134:          reg1 = XEXP (addr, 1);
                   2135:          addr = XEXP (addr, 0);
                   2136:        }
                   2137:       else if (GET_CODE (XEXP (addr, 0)) == REG)
                   2138:        {
                   2139:          reg1 = XEXP (addr, 0);
                   2140:          addr = XEXP (addr, 1);
                   2141:        }
                   2142:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                   2143:        {
                   2144:          reg1 = XEXP (addr, 1);
                   2145:          addr = XEXP (addr, 0);
                   2146:        }
                   2147:       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
                   2148:        {
                   2149:          if (reg1 == 0) reg1 = addr;
                   2150:          else reg2 = addr;
                   2151:          addr = 0;
                   2152:        }
                   2153:       if (offset != 0)
                   2154:        {
                   2155:          if (addr != 0) abort ();
                   2156:          addr = offset;
                   2157:        }
                   2158:       if ((reg1 && GET_CODE (reg1) == MULT)
                   2159:          || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
                   2160:        {
                   2161:          breg = reg2;
                   2162:          ireg = reg1;
                   2163:        }
                   2164:       else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
                   2165:        {
                   2166:          breg = reg1;
                   2167:          ireg = reg2;
                   2168:        }
                   2169: 
                   2170:       if (ireg != 0 || breg != 0)
                   2171:        {
                   2172:          int scale = 1;
                   2173: 
                   2174:          if (addr != 0)
                   2175:            {
1.1.1.3 ! root     2176:              if (flag_pic)
        !          2177:                output_pic_addr_const (file, addr, 0);
        !          2178: 
        !          2179:              else if (GET_CODE (addr) == LABEL_REF)
1.1       root     2180:                output_asm_label (addr);
1.1.1.3 ! root     2181: 
1.1       root     2182:              else
1.1.1.3 ! root     2183:                output_addr_const (file, addr);
1.1       root     2184:            }
                   2185: 
                   2186:          if (ireg != 0 && GET_CODE (ireg) == MULT)
                   2187:            {
                   2188:              scale = INTVAL (XEXP (ireg, 1));
                   2189:              ireg = XEXP (ireg, 0);
                   2190:            }
                   2191: 
                   2192:          /* The stack pointer can only appear as a base register,
                   2193:             never an index register, so exchange the regs if it is wrong. */
                   2194: 
                   2195:          if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM)
                   2196:            {
                   2197:              rtx tmp;
                   2198: 
                   2199:              tmp = breg;
                   2200:              breg = ireg;
                   2201:              ireg = tmp;
                   2202:            }
                   2203: 
                   2204:          /* output breg+ireg*scale */
                   2205:          PRINT_B_I_S (breg, ireg, scale, file);
                   2206:          break;
                   2207:        }
                   2208: 
                   2209:     case MULT:
                   2210:       {
                   2211:        int scale;
                   2212:        if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
                   2213:          {
                   2214:            scale = INTVAL (XEXP (addr, 0));
                   2215:            ireg = XEXP (addr, 1);
                   2216:          }
                   2217:        else
                   2218:          {
                   2219:            scale = INTVAL (XEXP (addr, 1));
                   2220:            ireg = XEXP (addr, 0);
                   2221:          }
                   2222:        output_addr_const (file, const0_rtx);
                   2223:        PRINT_B_I_S ((rtx) 0, ireg, scale, file);
                   2224:       }
                   2225:       break;
                   2226: 
                   2227:     default:
                   2228:       if (GET_CODE (addr) == CONST_INT
                   2229:          && INTVAL (addr) < 0x8000
                   2230:          && INTVAL (addr) >= -0x8000)
                   2231:        fprintf (file, "%d", INTVAL (addr));
                   2232:       else
                   2233:        {
                   2234:          if (flag_pic)
                   2235:            output_pic_addr_const (file, addr, 0);
                   2236:          else
                   2237:            output_addr_const (file, addr);
                   2238:        }
                   2239:     }
                   2240: }
                   2241: 
                   2242: /* Set the cc_status for the results of an insn whose pattern is EXP.
                   2243:    On the 80386, we assume that only test and compare insns, as well
1.1.1.3 ! root     2244:    as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT,
1.1       root     2245:    ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
                   2246:    Also, we assume that jumps, moves and sCOND don't affect the condition
                   2247:    codes.  All else clobbers the condition codes, by assumption.
                   2248: 
                   2249:    We assume that ALL integer add, minus, etc. instructions effect the
                   2250:    condition codes.  This MUST be consistent with i386.md.
                   2251: 
                   2252:    We don't record any float test or compare - the redundant test &
                   2253:    compare check in final.c does not handle stack-like regs correctly. */
                   2254: 
                   2255: void
                   2256: notice_update_cc (exp)
                   2257:      rtx exp;
                   2258: {
                   2259:   if (GET_CODE (exp) == SET)
                   2260:     {
                   2261:       /* Jumps do not alter the cc's.  */
                   2262:       if (SET_DEST (exp) == pc_rtx)
                   2263:        return;
                   2264:       /* Moving register or memory into a register:
                   2265:         it doesn't alter the cc's, but it might invalidate
                   2266:         the RTX's which we remember the cc's came from.
                   2267:         (Note that moving a constant 0 or 1 MAY set the cc's).  */
                   2268:       if (REG_P (SET_DEST (exp))
                   2269:          && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
                   2270:              || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
                   2271:        {
                   2272:          if (cc_status.value1
                   2273:              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
                   2274:            cc_status.value1 = 0;
                   2275:          if (cc_status.value2
                   2276:              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
                   2277:            cc_status.value2 = 0;
                   2278:          return;
                   2279:        }
                   2280:       /* Moving register into memory doesn't alter the cc's.
                   2281:         It may invalidate the RTX's which we remember the cc's came from.  */
                   2282:       if (GET_CODE (SET_DEST (exp)) == MEM
                   2283:          && (REG_P (SET_SRC (exp))
                   2284:              || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
                   2285:        {
                   2286:          if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
                   2287:            cc_status.value1 = 0;
                   2288:          if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
                   2289:            cc_status.value2 = 0;
                   2290:          return;
                   2291:        }
                   2292:       /* Function calls clobber the cc's.  */
                   2293:       else if (GET_CODE (SET_SRC (exp)) == CALL)
                   2294:        {
                   2295:          CC_STATUS_INIT;
                   2296:          return;
                   2297:        }
                   2298:       /* Tests and compares set the cc's in predictable ways.  */
                   2299:       else if (SET_DEST (exp) == cc0_rtx)
                   2300:        {
                   2301:          CC_STATUS_INIT;
                   2302:          cc_status.value1 = SET_SRC (exp);
                   2303:          return;
                   2304:        }
                   2305:       /* Certain instructions effect the condition codes. */
                   2306:       else if (GET_MODE (SET_SRC (exp)) == SImode
                   2307:               || GET_MODE (SET_SRC (exp)) == HImode
                   2308:               || GET_MODE (SET_SRC (exp)) == QImode)
                   2309:        switch (GET_CODE (SET_SRC (exp)))
                   2310:          {
                   2311:          case ASHIFTRT: case LSHIFTRT:
1.1.1.3 ! root     2312:          case ASHIFT:
1.1       root     2313:            /* Shifts on the 386 don't set the condition codes if the
                   2314:               shift count is zero. */
                   2315:            if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
                   2316:              {
                   2317:                CC_STATUS_INIT;
                   2318:                break;
                   2319:              }
                   2320:            /* We assume that the CONST_INT is non-zero (this rtx would
                   2321:               have been deleted if it were zero. */
                   2322: 
                   2323:          case PLUS: case MINUS: case NEG:
                   2324:          case AND: case IOR: case XOR:
                   2325:            cc_status.flags = CC_NO_OVERFLOW;
                   2326:            cc_status.value1 = SET_SRC (exp);
                   2327:            cc_status.value2 = SET_DEST (exp);
                   2328:            break;
                   2329: 
                   2330:          default:
                   2331:            CC_STATUS_INIT;
                   2332:          }
                   2333:       else
                   2334:        {
                   2335:          CC_STATUS_INIT;
                   2336:        }
                   2337:     }
                   2338:   else if (GET_CODE (exp) == PARALLEL
                   2339:           && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
                   2340:     {
                   2341:       if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
                   2342:        return;
                   2343:       if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
                   2344:        {
                   2345:          CC_STATUS_INIT;
                   2346:          if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
                   2347:            cc_status.flags |= CC_IN_80387;
                   2348:          else
                   2349:            cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
                   2350:          return;
                   2351:        }
                   2352:       CC_STATUS_INIT;
                   2353:     }
                   2354:   else
                   2355:     {
                   2356:       CC_STATUS_INIT;
                   2357:     }
                   2358: }
                   2359: 
                   2360: /* Split one or more DImode RTL references into pairs of SImode
                   2361:    references.  The RTL can be REG, offsettable MEM, integer constant, or
                   2362:    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
                   2363:    split and "num" is its length.  lo_half and hi_half are output arrays
                   2364:    that parallel "operands". */
                   2365: 
                   2366: void
                   2367: split_di (operands, num, lo_half, hi_half)
                   2368:      rtx operands[];
                   2369:      int num;
                   2370:      rtx lo_half[], hi_half[];
                   2371: {
                   2372:   while (num--)
                   2373:     {
                   2374:       if (GET_CODE (operands[num]) == REG)
                   2375:        {
                   2376:          lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
                   2377:          hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
                   2378:        }
                   2379:       else if (CONSTANT_P (operands[num]))
                   2380:        {
                   2381:          split_double (operands[num], &lo_half[num], &hi_half[num]);
                   2382:        }
                   2383:       else if (offsettable_memref_p (operands[num]))
                   2384:        {
                   2385:          lo_half[num] = operands[num];
                   2386:          hi_half[num] = adj_offsettable_operand (operands[num], 4);
                   2387:        }
                   2388:       else
                   2389:        abort();
                   2390:     }
                   2391: }
                   2392: 
                   2393: /* Return 1 if this is a valid binary operation on a 387.
                   2394:    OP is the expression matched, and MODE is its mode. */
                   2395: 
                   2396: int
                   2397: binary_387_op (op, mode)
                   2398:     register rtx op;
                   2399:     enum machine_mode mode;
                   2400: {
                   2401:   if (mode != VOIDmode && mode != GET_MODE (op))
                   2402:     return 0;
                   2403: 
                   2404:   switch (GET_CODE (op))
                   2405:     {
                   2406:     case PLUS:
                   2407:     case MINUS:
                   2408:     case MULT:
                   2409:     case DIV:
                   2410:       return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
                   2411: 
                   2412:     default:
                   2413:       return 0;
                   2414:     }
                   2415: }
                   2416: 
1.1.1.3 ! root     2417: 
1.1       root     2418: /* Return 1 if this is a valid shift or rotate operation on a 386.
                   2419:    OP is the expression matched, and MODE is its mode. */
                   2420: 
                   2421: int
                   2422: shift_op (op, mode)
                   2423:     register rtx op;
                   2424:     enum machine_mode mode;
                   2425: {
                   2426:   rtx operand = XEXP (op, 0);
                   2427: 
                   2428:   if (mode != VOIDmode && mode != GET_MODE (op))
                   2429:     return 0;
                   2430: 
                   2431:   if (GET_MODE (operand) != GET_MODE (op)
                   2432:       || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT)
                   2433:     return 0;
                   2434: 
                   2435:   return (GET_CODE (op) == ASHIFT
                   2436:          || GET_CODE (op) == ASHIFTRT
                   2437:          || GET_CODE (op) == LSHIFTRT
                   2438:          || GET_CODE (op) == ROTATE
                   2439:          || GET_CODE (op) == ROTATERT);
                   2440: }
                   2441: 
                   2442: /* Return 1 if OP is COMPARE rtx with mode VOIDmode.
                   2443:    MODE is not used.  */
                   2444: 
                   2445: int
                   2446: VOIDmode_compare_op (op, mode)
                   2447:     register rtx op;
                   2448:     enum machine_mode mode;
                   2449: {
                   2450:   return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode;
                   2451: }
                   2452: 
                   2453: /* Output code to perform a 387 binary operation in INSN, one of PLUS,
                   2454:    MINUS, MULT or DIV.  OPERANDS are the insn operands, where operands[3]
                   2455:    is the expression of the binary operation.  The output may either be
                   2456:    emitted here, or returned to the caller, like all output_* functions.
                   2457: 
                   2458:    There is no guarantee that the operands are the same mode, as they
                   2459:    might be within FLOAT or FLOAT_EXTEND expressions. */
                   2460: 
                   2461: char *
                   2462: output_387_binary_op (insn, operands)
                   2463:      rtx insn;
                   2464:      rtx *operands;
                   2465: {
                   2466:   rtx temp;
                   2467:   char *base_op;
                   2468:   static char buf[100];
                   2469: 
                   2470:   switch (GET_CODE (operands[3]))
                   2471:     {
                   2472:     case PLUS:
                   2473:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   2474:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   2475:        base_op = "fiadd";
                   2476:       else
                   2477:        base_op = "fadd";
                   2478:       break;
                   2479: 
                   2480:     case MINUS:
                   2481:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   2482:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   2483:        base_op = "fisub";
                   2484:       else
                   2485:        base_op = "fsub";
                   2486:       break;
                   2487: 
                   2488:     case MULT:
                   2489:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   2490:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   2491:        base_op = "fimul";
                   2492:       else
                   2493:        base_op = "fmul";
                   2494:       break;
                   2495: 
                   2496:     case DIV:
                   2497:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   2498:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   2499:        base_op = "fidiv";
                   2500:       else
                   2501:        base_op = "fdiv";
                   2502:       break;
                   2503: 
                   2504:     default:
                   2505:       abort ();
                   2506:     }
                   2507: 
                   2508:   strcpy (buf, base_op);
                   2509: 
                   2510:   switch (GET_CODE (operands[3]))
                   2511:     {
                   2512:     case MULT:
                   2513:     case PLUS:
                   2514:       if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
                   2515:        {
                   2516:          temp = operands[2];
                   2517:          operands[2] = operands[1];
                   2518:          operands[1] = temp;
                   2519:        }
                   2520: 
                   2521:       if (GET_CODE (operands[2]) == MEM)
                   2522:        return strcat (buf, AS1 (%z2,%2));
                   2523: 
                   2524:       if (NON_STACK_REG_P (operands[1]))
                   2525:        {
                   2526:          output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
                   2527:          RET;
                   2528:        }
                   2529:       else if (NON_STACK_REG_P (operands[2]))
                   2530:        {
                   2531:          output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
                   2532:          RET;
                   2533:        }
                   2534: 
                   2535:       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
                   2536:        return strcat (buf, AS2 (p,%2,%0));
                   2537: 
                   2538:       if (STACK_TOP_P (operands[0]))
1.1.1.3 ! root     2539:        return strcat (buf, AS2C (%y2,%0));
1.1       root     2540:       else
1.1.1.3 ! root     2541:        return strcat (buf, AS2C (%2,%0));
1.1       root     2542: 
                   2543:     case MINUS:
                   2544:     case DIV:
                   2545:       if (GET_CODE (operands[1]) == MEM)
                   2546:        return strcat (buf, AS1 (r%z1,%1));
                   2547: 
                   2548:       if (GET_CODE (operands[2]) == MEM)
                   2549:        return strcat (buf, AS1 (%z2,%2));
                   2550: 
                   2551:       if (NON_STACK_REG_P (operands[1]))
                   2552:        {
                   2553:          output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1)));
                   2554:          RET;
                   2555:        }
                   2556:       else if (NON_STACK_REG_P (operands[2]))
                   2557:        {
                   2558:          output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
                   2559:          RET;
                   2560:        }
                   2561: 
                   2562:       if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
                   2563:        abort ();
                   2564: 
                   2565:       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
                   2566:        return strcat (buf, AS2 (rp,%2,%0));
                   2567: 
                   2568:       if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
                   2569:        return strcat (buf, AS2 (p,%1,%0));
                   2570: 
                   2571:       if (STACK_TOP_P (operands[0]))
                   2572:        {
                   2573:          if (STACK_TOP_P (operands[1]))
1.1.1.3 ! root     2574:            return strcat (buf, AS2C (%y2,%0));
1.1       root     2575:          else
                   2576:            return strcat (buf, AS2 (r,%y1,%0));
                   2577:        }
                   2578:       else if (STACK_TOP_P (operands[1]))
1.1.1.3 ! root     2579:        return strcat (buf, AS2C (%1,%0));
1.1       root     2580:       else
                   2581:        return strcat (buf, AS2 (r,%2,%0));
                   2582: 
                   2583:     default:
                   2584:       abort ();
                   2585:     }
                   2586: }
                   2587: 
                   2588: /* Output code for INSN to convert a float to a signed int.  OPERANDS
                   2589:    are the insn operands.  The output may be SFmode or DFmode and the
                   2590:    input operand may be SImode or DImode.  As a special case, make sure
                   2591:    that the 387 stack top dies if the output mode is DImode, because the
                   2592:    hardware requires this.  */
                   2593: 
                   2594: char *
                   2595: output_fix_trunc (insn, operands)
                   2596:      rtx insn;
                   2597:      rtx *operands;
                   2598: {
                   2599:   int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
                   2600:   rtx xops[2];
                   2601: 
                   2602:   if (! STACK_TOP_P (operands[1]) ||
                   2603:       (GET_MODE (operands[0]) == DImode && ! stack_top_dies))
                   2604:     abort ();
                   2605: 
                   2606:   xops[0] = GEN_INT (12);
                   2607:   xops[1] = operands[4];
                   2608: 
                   2609:   output_asm_insn (AS1 (fnstc%W2,%2), operands);
                   2610:   output_asm_insn (AS2 (mov%L2,%2,%4), operands);
                   2611:   output_asm_insn (AS2 (mov%B1,%0,%h1), xops);
                   2612:   output_asm_insn (AS2 (mov%L4,%4,%3), operands);
                   2613:   output_asm_insn (AS1 (fldc%W3,%3), operands);
                   2614: 
                   2615:   if (NON_STACK_REG_P (operands[0]))
                   2616:     output_to_reg (operands[0], stack_top_dies);
                   2617:   else if (GET_CODE (operands[0]) == MEM)
                   2618:     {
                   2619:       if (stack_top_dies)
                   2620:        output_asm_insn (AS1 (fistp%z0,%0), operands);
                   2621:       else
                   2622:        output_asm_insn (AS1 (fist%z0,%0), operands);
                   2623:     }
                   2624:   else
                   2625:     abort ();
                   2626: 
                   2627:   return AS1 (fldc%W2,%2);
                   2628: }
                   2629: 
                   2630: /* Output code for INSN to compare OPERANDS.  The two operands might
                   2631:    not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
                   2632:    expression.  If the compare is in mode CCFPEQmode, use an opcode that
                   2633:    will not fault if a qNaN is present. */
                   2634: 
                   2635: char *
                   2636: output_float_compare (insn, operands)
                   2637:      rtx insn;
                   2638:      rtx *operands;
                   2639: {
                   2640:   int stack_top_dies;
                   2641:   rtx body = XVECEXP (PATTERN (insn), 0, 0);
                   2642:   int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
                   2643: 
                   2644:   if (! STACK_TOP_P (operands[0]))
                   2645:     abort ();
                   2646: 
                   2647:   stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
                   2648: 
                   2649:   if (STACK_REG_P (operands[1])
                   2650:       && stack_top_dies
                   2651:       && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))
                   2652:       && REGNO (operands[1]) != FIRST_STACK_REG)
                   2653:     {
                   2654:       /* If both the top of the 387 stack dies, and the other operand
                   2655:         is also a stack register that dies, then this must be a
                   2656:         `fcompp' float compare */
                   2657: 
                   2658:       if (unordered_compare)
                   2659:        output_asm_insn ("fucompp", operands);
                   2660:       else
                   2661:        output_asm_insn ("fcompp", operands);
                   2662:     }
                   2663:   else
                   2664:     {
                   2665:       static char buf[100];
                   2666: 
                   2667:       /* Decide if this is the integer or float compare opcode, or the
                   2668:         unordered float compare. */
                   2669: 
                   2670:       if (unordered_compare)
                   2671:        strcpy (buf, "fucom");
                   2672:       else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
                   2673:        strcpy (buf, "fcom");
                   2674:       else
                   2675:        strcpy (buf, "ficom");
                   2676: 
                   2677:       /* Modify the opcode if the 387 stack is to be popped. */
                   2678: 
                   2679:       if (stack_top_dies)
                   2680:        strcat (buf, "p");
                   2681: 
                   2682:       if (NON_STACK_REG_P (operands[1]))
                   2683:        output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
                   2684:       else
                   2685:         output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
                   2686:     }
                   2687: 
                   2688:   /* Now retrieve the condition code. */
                   2689: 
                   2690:   return output_fp_cc0_set (insn);
                   2691: }
                   2692: 
                   2693: /* Output opcodes to transfer the results of FP compare or test INSN
                   2694:    from the FPU to the CPU flags.  If TARGET_IEEE_FP, ensure that if the
                   2695:    result of the compare or test is unordered, no comparison operator
                   2696:    succeeds except NE.  Return an output template, if any.  */
                   2697: 
                   2698: char *
                   2699: output_fp_cc0_set (insn)
                   2700:      rtx insn;
                   2701: {
                   2702:   rtx xops[3];
                   2703:   rtx unordered_label;
                   2704:   rtx next;
                   2705:   enum rtx_code code;
                   2706: 
                   2707:   xops[0] = gen_rtx (REG, HImode, 0);
                   2708:   output_asm_insn (AS1 (fnsts%W0,%0), xops);
                   2709: 
                   2710:   if (! TARGET_IEEE_FP)
                   2711:     return "sahf";
                   2712: 
                   2713:   next = next_cc0_user (insn);
                   2714:   if (next == NULL_RTX)
                   2715:     abort ();
                   2716: 
                   2717:   if (GET_CODE (next) == JUMP_INSN
                   2718:       && GET_CODE (PATTERN (next)) == SET
                   2719:       && SET_DEST (PATTERN (next)) == pc_rtx
                   2720:       && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
                   2721:     {
                   2722:       code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
                   2723:     }
                   2724:   else if (GET_CODE (PATTERN (next)) == SET)
                   2725:     {
                   2726:       code = GET_CODE (SET_SRC (PATTERN (next)));
                   2727:     }
                   2728:   else
                   2729:     abort ();
                   2730: 
                   2731:   xops[0] = gen_rtx (REG, QImode, 0);
                   2732: 
                   2733:   switch (code)
                   2734:     {
                   2735:     case GT:
                   2736:       xops[1] = GEN_INT (0x45);
                   2737:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
                   2738:       /* je label */
                   2739:       break;
                   2740: 
                   2741:     case LT:
                   2742:       xops[1] = GEN_INT (0x45);
                   2743:       xops[2] = GEN_INT (0x01);
                   2744:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
                   2745:       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
                   2746:       /* je label */
                   2747:       break;
                   2748: 
                   2749:     case GE:
                   2750:       xops[1] = GEN_INT (0x05);
                   2751:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
                   2752:       /* je label */
                   2753:       break;
                   2754: 
                   2755:     case LE:
                   2756:       xops[1] = GEN_INT (0x45);
                   2757:       xops[2] = GEN_INT (0x40);
                   2758:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
                   2759:       output_asm_insn (AS1 (dec%B0,%h0), xops);
                   2760:       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
                   2761:       /* jb label */
                   2762:       break;
                   2763: 
                   2764:     case EQ:
                   2765:       xops[1] = GEN_INT (0x45);
                   2766:       xops[2] = GEN_INT (0x40);
                   2767:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
                   2768:       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
                   2769:       /* je label */
                   2770:       break;
                   2771: 
                   2772:     case NE:
                   2773:       xops[1] = GEN_INT (0x44);
                   2774:       xops[2] = GEN_INT (0x40);
                   2775:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
                   2776:       output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
                   2777:       /* jne label */
                   2778:       break;
                   2779: 
                   2780:     case GTU:
                   2781:     case LTU:
                   2782:     case GEU:
                   2783:     case LEU:
                   2784:     default:
                   2785:       abort ();
                   2786:     }
                   2787:   RET;
                   2788: }
                   2789: 
                   2790: #define MAX_386_STACK_LOCALS 2
                   2791: 
                   2792: static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
                   2793: 
1.1.1.2   root     2794: /* Define the structure for the machine field in struct function.  */
                   2795: struct machine_function
                   2796: {
                   2797:   rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
                   2798: };
                   2799: 
                   2800: /* Functions to save and restore i386_stack_locals.
                   2801:    These will be called, via pointer variables,
                   2802:    from push_function_context and pop_function_context.  */
                   2803: 
                   2804: void
                   2805: save_386_machine_status (p)
                   2806:      struct function *p;
                   2807: {
                   2808:   p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals);
1.1.1.3 ! root     2809:   bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals,
1.1.1.2   root     2810:         sizeof i386_stack_locals);
                   2811: }
                   2812: 
                   2813: void
                   2814: restore_386_machine_status (p)
                   2815:      struct function *p;
                   2816: {
1.1.1.3 ! root     2817:   bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals,
1.1.1.2   root     2818:         sizeof i386_stack_locals);
                   2819:   free (p->machine);
                   2820: }
                   2821: 
1.1       root     2822: /* Clear stack slot assignments remembered from previous functions.
                   2823:    This is called from INIT_EXPANDERS once before RTL is emitted for each
1.1.1.2   root     2824:    function.  */
1.1       root     2825: 
                   2826: void
                   2827: clear_386_stack_locals ()
                   2828: {
                   2829:   enum machine_mode mode;
                   2830:   int n;
                   2831: 
                   2832:   for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
                   2833:        mode = (enum machine_mode) ((int) mode + 1))
                   2834:     for (n = 0; n < MAX_386_STACK_LOCALS; n++)
                   2835:       i386_stack_locals[(int) mode][n] = NULL_RTX;
1.1.1.2   root     2836: 
                   2837:   /* Arrange to save and restore i386_stack_locals around nested functions.  */
                   2838:   save_machine_status = save_386_machine_status;
                   2839:   restore_machine_status = restore_386_machine_status;
1.1       root     2840: }
                   2841: 
                   2842: /* Return a MEM corresponding to a stack slot with mode MODE.
                   2843:    Allocate a new slot if necessary.
                   2844: 
                   2845:    The RTL for a function can have several slots available: N is
                   2846:    which slot to use.  */
                   2847: 
                   2848: rtx
                   2849: assign_386_stack_local (mode, n)
                   2850:      enum machine_mode mode;
                   2851:      int n;
                   2852: {
                   2853:   if (n < 0 || n >= MAX_386_STACK_LOCALS)
                   2854:     abort ();
                   2855: 
                   2856:   if (i386_stack_locals[(int) mode][n] == NULL_RTX)
                   2857:     i386_stack_locals[(int) mode][n]
                   2858:       = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
                   2859: 
                   2860:   return i386_stack_locals[(int) mode][n];
                   2861: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.