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

1.1       root        1: /* Subroutines for insn-output.c for Intel 80386.
                      2:    Copyright (C) 1988 Free Software Foundation, Inc.
                      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 "config.h"
                     22: #include "rtl.h"
                     23: #include "regs.h"
                     24: #include "hard-reg-set.h"
                     25: #include "real.h"
                     26: #include "insn-config.h"
                     27: #include "conditions.h"
                     28: #include "insn-flags.h"
                     29: #include "output.h"
                     30: #include "insn-attr.h"
                     31: #include "tree.h"
                     32: #include "flags.h"
                     33: 
1.1.1.2   root       34: #ifdef EXTRA_CONSTRAINT
                     35: /* If EXTRA_CONSTRAINT is defined, then the 'S'
                     36:    constraint in REG_CLASS_FROM_LETTER will no longer work, and various
                     37:    asm statements that need 'S' for class SIREG will break.  */
                     38:  #error EXTRA_CONSTRAINT conflicts with S constraint letter
                     39: #endif
                     40: 
1.1       root       41: #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
                     42: 
                     43: extern FILE *asm_out_file;
                     44: extern char *strcat ();
                     45: 
                     46: char *singlemove_string ();
                     47: char *output_move_const_single ();
1.1.1.3 ! root       48: char *output_fp_cc0_set ();
1.1       root       49: 
                     50: static char *hi_reg_name[] = HI_REGISTER_NAMES;
                     51: static char *qi_reg_name[] = QI_REGISTER_NAMES;
                     52: static char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
                     53: 
                     54: /* Array of the smallest class containing reg number REGNO, indexed by
                     55:    REGNO.  Used by REGNO_REG_CLASS in i386.h. */
                     56: 
                     57: enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
                     58: {
                     59:   /* ax, dx, cx, bx */
1.1.1.2   root       60:   AREG, DREG, CREG, BREG,
1.1       root       61:   /* si, di, bp, sp */
                     62:   SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
                     63:   /* FP registers */
                     64:   FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
                     65:   FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,       
                     66:   /* arg pointer */
                     67:   INDEX_REGS
                     68: };
1.1.1.3 ! root       69: 
        !            70: /* Test and compare insns in i386.md store the information needed to
        !            71:    generate branch and scc insns here.  */
        !            72: 
        !            73: struct rtx_def *i386_compare_op0, *i386_compare_op1;
        !            74: struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
1.1       root       75: 
                     76: /* Output an insn whose source is a 386 integer register.  SRC is the
                     77:    rtx for the register, and TEMPLATE is the op-code template.  SRC may
                     78:    be either SImode or DImode.
                     79: 
                     80:    The template will be output with operands[0] as SRC, and operands[1]
                     81:    as a pointer to the top of the 386 stack.  So a call from floatsidf2
                     82:    would look like this:
                     83: 
                     84:       output_op_from_reg (operands[1], AS1 (fild%z0,%1));
                     85: 
                     86:    where %z0 corresponds to the caller's operands[1], and is used to
                     87:    emit the proper size suffix.
                     88: 
                     89:    ??? Extend this to handle HImode - a 387 can load and store HImode
                     90:    values directly. */
                     91: 
                     92: void
                     93: output_op_from_reg (src, template)
                     94:      rtx src;
                     95:      char *template;
                     96: {
                     97:   rtx xops[4];
                     98: 
                     99:   xops[0] = src;
                    100:   xops[1] = AT_SP (Pmode);
                    101:   xops[2] = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (src)));
                    102:   xops[3] = stack_pointer_rtx;
                    103: 
                    104:   if (GET_MODE_SIZE (GET_MODE (src)) > UNITS_PER_WORD)
                    105:     {
                    106:       rtx high = gen_rtx (REG, SImode, REGNO (src) + 1);
                    107:       output_asm_insn (AS1 (push%L0,%0), &high);
                    108:     }
                    109:   output_asm_insn (AS1 (push%L0,%0), &src);
                    110: 
                    111:   output_asm_insn (template, xops);
                    112: 
                    113:   output_asm_insn (AS2 (add%L3,%2,%3), xops);
                    114: }
                    115: 
                    116: /* Output an insn to pop an value from the 387 top-of-stack to 386
                    117:    register DEST. The 387 register stack is popped if DIES is true.  If
                    118:    the mode of DEST is an integer mode, a `fist' integer store is done,
                    119:    otherwise a `fst' float store is done. */
                    120: 
                    121: void
                    122: output_to_reg (dest, dies)
                    123:      rtx dest;
                    124:      int dies;
                    125: {
                    126:   rtx xops[4];
                    127: 
                    128:   xops[0] = AT_SP (Pmode);
                    129:   xops[1] = stack_pointer_rtx;
                    130:   xops[2] = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (dest)));
                    131:   xops[3] = dest;
                    132: 
                    133:   output_asm_insn (AS2 (sub%L1,%2,%1), xops);
                    134: 
                    135:   if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
                    136:     {
                    137:       if (dies)
                    138:        output_asm_insn (AS1 (fistp%z3,%y0), xops);
                    139:       else
                    140:        output_asm_insn (AS1 (fist%z3,%y0), xops);
                    141:     }
                    142:   else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)
                    143:     {
                    144:       if (dies)
                    145:        output_asm_insn (AS1 (fstp%z3,%y0), xops);
                    146:       else
                    147:        output_asm_insn (AS1 (fst%z3,%y0), xops);
                    148:     }
                    149:   else
                    150:     abort ();
                    151: 
                    152:   output_asm_insn (AS1 (pop%L0,%0), &dest);
                    153: 
                    154:   if (GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD)
                    155:     {
                    156:       dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
                    157:       output_asm_insn (AS1 (pop%L0,%0), &dest);
                    158:     }
                    159: }
                    160: 
                    161: char *
                    162: singlemove_string (operands)
                    163:      rtx *operands;
                    164: {
                    165:   rtx x;
                    166:   if (GET_CODE (operands[0]) == MEM
                    167:       && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
                    168:     {
                    169:       if (XEXP (x, 0) != stack_pointer_rtx)
                    170:        abort ();
                    171:       return "push%L1 %1";
                    172:     }
                    173:   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    174:     {
                    175:       return output_move_const_single (operands);
                    176:     }
                    177:   else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
                    178:     return AS2 (mov%L0,%1,%0);
                    179:   else if (CONSTANT_P (operands[1]))
                    180:     return AS2 (mov%L0,%1,%0);
                    181:   else
                    182:     {
                    183:       output_asm_insn ("push%L1 %1", operands);
                    184:       return "pop%L0 %0";
                    185:     }
                    186: }
                    187: 
                    188: /* Return a REG that occurs in ADDR with coefficient 1.
                    189:    ADDR can be effectively incremented by incrementing REG.  */
                    190: 
                    191: static rtx
                    192: find_addr_reg (addr)
                    193:      rtx addr;
                    194: {
                    195:   while (GET_CODE (addr) == PLUS)
                    196:     {
                    197:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    198:        addr = XEXP (addr, 0);
                    199:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                    200:        addr = XEXP (addr, 1);
                    201:       else if (CONSTANT_P (XEXP (addr, 0)))
                    202:        addr = XEXP (addr, 1);
                    203:       else if (CONSTANT_P (XEXP (addr, 1)))
                    204:        addr = XEXP (addr, 0);
                    205:       else
                    206:        abort ();
                    207:     }
                    208:   if (GET_CODE (addr) == REG)
                    209:     return addr;
                    210:   abort ();
                    211: }
                    212: 
                    213: /* Output an insn to add the constant N to the register X.  */
                    214: 
                    215: static void
                    216: asm_add (n, x)
                    217:      int n;
                    218:      rtx x;
                    219: {
                    220:   rtx xops[2];
                    221:   xops[1] = x;
                    222:   if (n < 0)
                    223:     {
                    224:       xops[0] = gen_rtx (CONST_INT, VOIDmode, -n);
                    225:       output_asm_insn (AS2 (sub%L0,%0,%1), xops);
                    226:     }
                    227:   else if (n > 0)
                    228:     {
                    229:       xops[0] = gen_rtx (CONST_INT, VOIDmode, n);
                    230:       output_asm_insn (AS2 (add%L0,%0,%1), xops);
                    231:     }
                    232: }
                    233: 
                    234: /* Output assembler code to perform a doubleword move insn
                    235:    with operands OPERANDS.  */
                    236: 
                    237: char *
                    238: output_move_double (operands)
                    239:      rtx *operands;
                    240: {
                    241:   enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    242:   rtx latehalf[2];
                    243:   rtx addreg0 = 0, addreg1 = 0;
                    244: 
                    245:   /* First classify both operands.  */
                    246: 
                    247:   if (REG_P (operands[0]))
                    248:     optype0 = REGOP;
                    249:   else if (offsettable_memref_p (operands[0]))
                    250:     optype0 = OFFSOP;
                    251:   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
                    252:     optype0 = POPOP;
                    253:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
                    254:     optype0 = PUSHOP;
                    255:   else if (GET_CODE (operands[0]) == MEM)
                    256:     optype0 = MEMOP;
                    257:   else
                    258:     optype0 = RNDOP;
                    259: 
                    260:   if (REG_P (operands[1]))
                    261:     optype1 = REGOP;
                    262:   else if (CONSTANT_P (operands[1]))
                    263:     optype1 = CNSTOP;
                    264:   else if (offsettable_memref_p (operands[1]))
                    265:     optype1 = OFFSOP;
                    266:   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
                    267:     optype1 = POPOP;
                    268:   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
                    269:     optype1 = PUSHOP;
                    270:   else if (GET_CODE (operands[1]) == MEM)
                    271:     optype1 = MEMOP;
                    272:   else
                    273:     optype1 = RNDOP;
                    274: 
                    275:   /* Check for the cases that the operand constraints are not
                    276:      supposed to allow to happen.  Abort if we get one,
                    277:      because generating code for these cases is painful.  */
                    278: 
                    279:   if (optype0 == RNDOP || optype1 == RNDOP)
                    280:     abort ();
                    281: 
                    282:   /* If one operand is decrementing and one is incrementing
                    283:      decrement the former register explicitly
                    284:      and change that operand into ordinary indexing.  */
                    285: 
                    286:   if (optype0 == PUSHOP && optype1 == POPOP)
                    287:     {
                    288:       operands[0] = XEXP (XEXP (operands[0], 0), 0);
                    289:       asm_add (-8, operands[0]);
                    290:       operands[0] = gen_rtx (MEM, DImode, operands[0]);
                    291:       optype0 = OFFSOP;
                    292:     }
                    293:   if (optype0 == POPOP && optype1 == PUSHOP)
                    294:     {
                    295:       operands[1] = XEXP (XEXP (operands[1], 0), 0);
                    296:       asm_add (-8, operands[1]);
                    297:       operands[1] = gen_rtx (MEM, DImode, operands[1]);
                    298:       optype1 = OFFSOP;
                    299:     }
                    300: 
                    301:   /* If an operand is an unoffsettable memory ref, find a register
                    302:      we can increment temporarily to make it refer to the second word.  */
                    303: 
                    304:   if (optype0 == MEMOP)
                    305:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    306: 
                    307:   if (optype1 == MEMOP)
                    308:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    309: 
                    310:   /* Ok, we can do one word at a time.
                    311:      Normally we do the low-numbered word first,
                    312:      but if either operand is autodecrementing then we
                    313:      do the high-numbered word first.
                    314: 
                    315:      In either case, set up in LATEHALF the operands to use
                    316:      for the high-numbered word and in some cases alter the
                    317:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    318: 
                    319:   if (optype0 == REGOP)
                    320:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    321:   else if (optype0 == OFFSOP)
                    322:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    323:   else
                    324:     latehalf[0] = operands[0];
                    325: 
                    326:   if (optype1 == REGOP)
                    327:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    328:   else if (optype1 == OFFSOP)
                    329:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    330:   else if (optype1 == CNSTOP)
                    331:     {
                    332:       if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    333:        split_double (operands[1], &operands[1], &latehalf[1]);
                    334:       else if (CONSTANT_P (operands[1]))
1.1.1.2   root      335:        {
                    336:          if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0)
                    337:            latehalf[1] = constm1_rtx;
                    338:          else
                    339:            latehalf[1] = const0_rtx;
                    340:        }
1.1       root      341:     }
                    342:   else
                    343:     latehalf[1] = operands[1];
                    344: 
                    345:   /* If insn is effectively movd N (sp),-(sp) then we will do the
                    346:      high word first.  We should use the adjusted operand 1 (which is N+4 (sp))
                    347:      for the low word as well, to compensate for the first decrement of sp.  */
                    348:   if (optype0 == PUSHOP
                    349:       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
                    350:       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
                    351:     operands[1] = latehalf[1];
                    352: 
                    353:   /* If one or both operands autodecrementing,
                    354:      do the two words, high-numbered first.  */
                    355: 
                    356:   /* Likewise,  the first move would clobber the source of the second one,
                    357:      do them in the other order.  This happens only for registers;
                    358:      such overlap can't happen in memory unless the user explicitly
                    359:      sets it up, and that is an undefined circumstance.  */
                    360: 
                    361:   if (optype0 == PUSHOP || optype1 == PUSHOP
                    362:       || (optype0 == REGOP && optype1 == REGOP
                    363:          && REGNO (operands[0]) == REGNO (latehalf[1])))
                    364:     {
                    365:       /* Make any unoffsettable addresses point at high-numbered word.  */
                    366:       if (addreg0)
                    367:        asm_add (4, addreg0);
                    368:       if (addreg1)
                    369:        asm_add (4, addreg1);
                    370: 
                    371:       /* Do that word.  */
                    372:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    373: 
                    374:       /* Undo the adds we just did.  */
                    375:       if (addreg0)
                    376:          asm_add (-4, addreg0);
                    377:       if (addreg1)
                    378:        asm_add (-4, addreg1);
                    379: 
                    380:       /* Do low-numbered word.  */
                    381:       return singlemove_string (operands);
                    382:     }
                    383: 
                    384:   /* Normal case: do the two words, low-numbered first.  */
                    385: 
                    386:   output_asm_insn (singlemove_string (operands), operands);
                    387: 
                    388:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    389:   if (addreg0)
                    390:     asm_add (4, addreg0);
                    391:   if (addreg1)
                    392:     asm_add (4, addreg1);
                    393: 
                    394:   /* Do that word.  */
                    395:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    396: 
                    397:   /* Undo the adds we just did.  */
                    398:   if (addreg0)
                    399:     asm_add (-4, addreg0);
                    400:   if (addreg1)
                    401:     asm_add (-4, addreg1);
                    402: 
                    403:   return "";
                    404: }
                    405: 
                    406: int
                    407: standard_80387_constant_p (x)
                    408:      rtx x;
                    409: {
                    410:   union real_extract u;
                    411:   register double d;
                    412: 
                    413:   bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u);
                    414:   d = u.d;
                    415: 
                    416:   if (d == 0)
                    417:     return 1;
                    418: 
                    419:   if (d == 1)
                    420:     return 2;
                    421: 
                    422:   /* Note that on the 80387, other constants, such as pi,
                    423:      are much slower to load as standard constants
                    424:      than to load from doubles in memory!  */
                    425: 
                    426:   return 0;
                    427: }
                    428: 
                    429: char *
                    430: output_move_const_single (operands)
                    431:      rtx *operands;
                    432: {
                    433:   if (FP_REG_P (operands[0]))
                    434:     {
                    435:       int conval = standard_80387_constant_p (operands[1]);
                    436: 
                    437:       if (conval == 1)
                    438:        return "fldz";
                    439: 
                    440:       if (conval == 2)
                    441:        return "fld1";
                    442:     }
                    443:   if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    444:     {
                    445:       union { int i[2]; double d;} u1;
                    446:       union { int i; float f;} u2;
                    447:       u1.i[0] = CONST_DOUBLE_LOW (operands[1]);
                    448:       u1.i[1] = CONST_DOUBLE_HIGH (operands[1]);
                    449:       u2.f = u1.d;
                    450:       operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i);
                    451:     }
                    452:   return singlemove_string (operands);
                    453: }
                    454: 
                    455: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
                    456:    reference and a constant.  */
                    457: 
                    458: int
                    459: symbolic_operand (op, mode)
                    460:      register rtx op;
                    461:      enum machine_mode mode;
                    462: {
                    463:   switch (GET_CODE (op))
                    464:     {
                    465:     case SYMBOL_REF:
                    466:     case LABEL_REF:
                    467:       return 1;
                    468:     case CONST:
                    469:       op = XEXP (op, 0);
                    470:       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
                    471:               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
                    472:              && GET_CODE (XEXP (op, 1)) == CONST_INT);
                    473:     default:
                    474:       return 0;
                    475:     }
                    476: }
                    477: 
                    478: /* Returns 1 if OP contains a symbol reference */
                    479: 
                    480: int
                    481: symbolic_reference_mentioned_p (op)
                    482:      rtx op;
                    483: {
                    484:   register char *fmt;
                    485:   register int i;
                    486: 
                    487:   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
                    488:     return 1;
                    489: 
                    490:   fmt = GET_RTX_FORMAT (GET_CODE (op));
                    491:   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
                    492:     {
                    493:       if (fmt[i] == 'E')
                    494:        {
                    495:          register int j;
                    496: 
                    497:          for (j = XVECLEN (op, i) - 1; j >= 0; j--)
                    498:            if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
                    499:              return 1;
                    500:        }
                    501:       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
                    502:        return 1;
                    503:     }
                    504: 
                    505:   return 0;
                    506: }
                    507: 
                    508: /* Return a legitimate reference for ORIG (an address) using the
                    509:    register REG.  If REG is 0, a new pseudo is generated.
                    510: 
                    511:    There are three types of references that must be handled:
                    512: 
                    513:    1. Global data references must load the address from the GOT, via
                    514:       the PIC reg.  An insn is emitted to do this load, and the reg is
                    515:       returned.
                    516: 
                    517:    2. Static data references must compute the address as an offset
                    518:       from the GOT, whose base is in the PIC reg.  An insn is emitted to
                    519:       compute the address into a reg, and the reg is returned.  Static
                    520:       data objects have SYMBOL_REF_FLAG set to differentiate them from
                    521:       global data objects.
                    522: 
                    523:    3. Constant pool addresses must be handled special.  They are
                    524:       considered legitimate addresses, but only if not used with regs.
                    525:       When printed, the output routines know to print the reference with the
                    526:       PIC reg, even though the PIC reg doesn't appear in the RTL.
                    527: 
                    528:    GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
                    529:    reg also appears in the address (except for constant pool references,
                    530:    noted above).
                    531: 
                    532:    "switch" statements also require special handling when generating
                    533:    PIC code.  See comments by the `casesi' insn in i386.md for details.  */
                    534: 
                    535: rtx
                    536: legitimize_pic_address (orig, reg)
                    537:      rtx orig;
                    538:      rtx reg;
                    539: {
                    540:   rtx addr = orig;
                    541:   rtx new = orig;
                    542: 
                    543:   if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
                    544:     {
                    545:       if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
                    546:        reg = new = orig;
                    547:       else
                    548:        {
                    549:          if (reg == 0)
                    550:            reg = gen_reg_rtx (Pmode);
                    551: 
                    552:          if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
                    553:            new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
                    554:          else
                    555:            new = gen_rtx (MEM, Pmode,
                    556:                           gen_rtx (PLUS, Pmode,
                    557:                                    pic_offset_table_rtx, orig));
                    558: 
                    559:          emit_move_insn (reg, new);
                    560:        }
                    561:       current_function_uses_pic_offset_table = 1;
                    562:       return reg;
                    563:     }
                    564:   else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
                    565:     {
                    566:       rtx base;
                    567: 
                    568:       if (GET_CODE (addr) == CONST)
                    569:        {
                    570:          addr = XEXP (addr, 0);
                    571:          if (GET_CODE (addr) != PLUS)
                    572:            abort ();
                    573:        }
                    574: 
                    575:       if (XEXP (addr, 0) == pic_offset_table_rtx)
                    576:        return orig;
                    577: 
                    578:       if (reg == 0)
                    579:        reg = gen_reg_rtx (Pmode);
                    580: 
                    581:       base = legitimize_pic_address (XEXP (addr, 0), reg);
                    582:       addr = legitimize_pic_address (XEXP (addr, 1), base == reg ? 0 : reg);
                    583: 
                    584:       if (GET_CODE (addr) == CONST_INT)
                    585:        return plus_constant (base, INTVAL (addr));
                    586: 
                    587:       if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
                    588:        {
                    589:          base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
                    590:          addr = XEXP (addr, 1);
                    591:        }
                    592:        return gen_rtx (PLUS, Pmode, base, addr);
                    593:     }
                    594:   return new;
                    595: }
                    596: 
                    597: /* Emit insns to move operands[1] into operands[0].  */
                    598: 
                    599: void
                    600: emit_pic_move (operands, mode)
                    601:      rtx *operands;
                    602:      enum machine_mode mode;
                    603: {
                    604:   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
                    605: 
                    606:   if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
                    607:     operands[1] = (rtx) force_reg (SImode, operands[1]);
                    608:   else
                    609:     operands[1] = legitimize_pic_address (operands[1], temp);
                    610: }
                    611: 
                    612: /* This function generates the assembly code for function entry.
                    613:    FILE is an stdio stream to output the code to.
                    614:    SIZE is an int: how many units of temporary storage to allocate. */
                    615: 
                    616: void
                    617: function_prologue (file, size)
                    618:      FILE *file;
                    619:      int size;
                    620: {
                    621:   register int regno;
                    622:   int limit;
                    623:   rtx xops[4];
1.1.1.3 ! root      624:   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
        !           625:                                  || current_function_uses_const_pool);
1.1       root      626: 
                    627:   xops[0] = stack_pointer_rtx;
                    628:   xops[1] = frame_pointer_rtx;
                    629:   xops[2] = gen_rtx (CONST_INT, VOIDmode, size);
                    630:   if (frame_pointer_needed)
                    631:     {
                    632:       output_asm_insn ("push%L1 %1", xops);
                    633:       output_asm_insn (AS2 (mov%L0,%0,%1), xops);
                    634:     }
                    635: 
                    636:   if (size)
                    637:     output_asm_insn (AS2 (sub%L0,%2,%0), xops);
                    638: 
                    639:   /* Note If use enter it is NOT reversed args.
                    640:      This one is not reversed from intel!!
                    641:      I think enter is slower.  Also sdb doesn't like it.
                    642:      But if you want it the code is:
                    643:      {
                    644:      xops[3] = const0_rtx;
                    645:      output_asm_insn ("enter %2,%3", xops);
                    646:      }
                    647:      */
                    648:   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
                    649:   for (regno = limit - 1; regno >= 0; regno--)
                    650:     if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root      651:        || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1       root      652:       {
                    653:        xops[0] = gen_rtx (REG, SImode, regno);
                    654:        output_asm_insn ("push%L0 %0", xops);
                    655:       }
                    656: 
1.1.1.3 ! root      657:   if (pic_reg_used)
1.1       root      658:     {
                    659:       xops[0] = pic_offset_table_rtx;
                    660:       xops[1] = (rtx) gen_label_rtx ();
                    661: 
                    662:       output_asm_insn (AS1 (call,%P1), xops);
                    663:       ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1]));
                    664:       output_asm_insn (AS1 (pop%L0,%0), xops);
                    665:       output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
                    666:     }
                    667: }
                    668: 
                    669: /* Return 1 if it is appropriate to emit `ret' instructions in the
                    670:    body of a function.  Do this only if the epilogue is simple, needing a
                    671:    couple of insns.  Prior to reloading, we can't tell how many registers
                    672:    must be saved, so return 0 then.
                    673: 
                    674:    If NON_SAVING_SETJMP is defined and true, then it is not possible
                    675:    for the epilogue to be simple, so return 0.  This is a special case
                    676:    since NON_SAVING_SETJMP will not cause regs_ever_live to change until
                    677:    final, but jump_optimize may need to know sooner if a `return' is OK.  */
                    678: 
                    679: int
                    680: simple_386_epilogue ()
                    681: {
                    682:   int regno;
                    683:   int nregs = 0;
                    684:   int reglimit = (frame_pointer_needed
                    685:                  ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
1.1.1.3 ! root      686:   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
        !           687:                                  || current_function_uses_const_pool);
1.1       root      688: 
                    689: #ifdef NON_SAVING_SETJMP
                    690:   if (NON_SAVING_SETJMP && current_function_calls_setjmp)
                    691:     return 0;
                    692: #endif
                    693: 
                    694:   if (! reload_completed)
                    695:     return 0;
                    696: 
                    697:   for (regno = reglimit - 1; regno >= 0; regno--)
                    698:     if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root      699:        || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1       root      700:       nregs++;
                    701: 
                    702:   return nregs == 0 || ! frame_pointer_needed;
                    703: }
                    704: 
                    705: /* This function generates the assembly code for function exit.
                    706:    FILE is an stdio stream to output the code to.
                    707:    SIZE is an int: how many units of temporary storage to deallocate. */
                    708: 
                    709: void
                    710: function_epilogue (file, size)
                    711:      FILE *file;
                    712:      int size;
                    713: {
                    714:   register int regno;
                    715:   register int nregs, limit;
                    716:   int offset;
                    717:   rtx xops[3];
1.1.1.3 ! root      718:   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
        !           719:                                  || current_function_uses_const_pool);
1.1       root      720: 
                    721:   /* Compute the number of registers to pop */
                    722: 
                    723:   limit = (frame_pointer_needed
                    724:           ? FRAME_POINTER_REGNUM
                    725:           : STACK_POINTER_REGNUM);
                    726: 
                    727:   nregs = 0;
                    728: 
                    729:   for (regno = limit - 1; regno >= 0; regno--)
                    730:     if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root      731:        || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1       root      732:       nregs++;
                    733: 
                    734:   /* sp is often  unreliable so we must go off the frame pointer,
                    735:    */
                    736: 
                    737:   /* In reality, we may not care if sp is unreliable, because we can
                    738:      restore the register relative to the frame pointer.  In theory,
                    739:      since each move is the same speed as a pop, and we don't need the
                    740:      leal, this is faster.  For now restore multiple registers the old
                    741:      way. */
                    742: 
                    743:   offset = -size - (nregs * UNITS_PER_WORD);
                    744: 
                    745:   xops[2] = stack_pointer_rtx;
                    746: 
                    747:   if (nregs > 1 || ! frame_pointer_needed)
                    748:     {
                    749:       if (frame_pointer_needed)
                    750:        {
                    751:          xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset);
                    752:          output_asm_insn (AS2 (lea%L2,%0,%2), xops);
                    753:        }
                    754: 
                    755:       for (regno = 0; regno < limit; regno++)
                    756:        if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root      757:            || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1       root      758:          {
                    759:            xops[0] = gen_rtx (REG, SImode, regno);
                    760:            output_asm_insn ("pop%L0 %0", xops);
                    761:          }
                    762:     }
                    763:   else
                    764:     for (regno = 0; regno < limit; regno++)
                    765:       if ((regs_ever_live[regno] && ! call_used_regs[regno])
1.1.1.3 ! root      766:          || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1.1       root      767:        {
                    768:          xops[0] = gen_rtx (REG, SImode, regno);
                    769:          xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
                    770:          output_asm_insn (AS2 (mov%L0,%1,%0), xops);
                    771:          offset += 4;
                    772:        }
                    773: 
                    774:   if (frame_pointer_needed)
                    775:     {
                    776:       /* On i486, mov & pop is faster than "leave". */
                    777: 
                    778:       if (TARGET_486)
                    779:        {
                    780:          xops[0] = frame_pointer_rtx;
                    781:          output_asm_insn (AS2 (mov%L2,%0,%2), xops);
                    782:          output_asm_insn ("pop%L0 %0", xops);
                    783:        }
                    784:       else
                    785:        output_asm_insn ("leave", xops);
                    786:     }
                    787:   else if (size)
                    788:     {
                    789:       /* If there is no frame pointer, we must still release the frame. */
                    790: 
                    791:       xops[0] = gen_rtx (CONST_INT, VOIDmode, size);
                    792:       output_asm_insn (AS2 (add%L2,%0,%2), xops);
                    793:     }
                    794: 
                    795:   if (current_function_pops_args && current_function_args_size)
                    796:     {
                    797:       xops[1] = gen_rtx (CONST_INT, VOIDmode, current_function_pops_args);
                    798: 
                    799:       /* i386 can only pop 32K bytes (maybe 64K?  Is it signed?).  If
                    800:         asked to pop more, pop return address, do explicit add, and jump
                    801:         indirectly to the caller. */
                    802: 
                    803:       if (current_function_pops_args >= 32768)
                    804:        {
                    805:          /* ??? Which register to use here? */
                    806:          xops[0] = gen_rtx (REG, SImode, 2);
                    807:          output_asm_insn ("pop%L0 %0", xops);
                    808:          output_asm_insn (AS2 (add%L2,%1,%2), xops);
                    809:          output_asm_insn ("jmp %*%0", xops);
                    810:        }
                    811:       else
                    812:          output_asm_insn ("ret %1", xops);
                    813:     }
                    814:   else
                    815:     output_asm_insn ("ret", xops);
                    816: }
                    817: 
                    818: /* Print an integer constant expression in assembler syntax.  Addition
                    819:    and subtraction are the only arithmetic that may appear in these
                    820:    expressions.  FILE is the stdio stream to write to, X is the rtx, and
                    821:    CODE is the operand print code from the output string.  */
                    822: 
                    823: static void
                    824: output_pic_addr_const (file, x, code)
                    825:      FILE *file;
                    826:      rtx x;
                    827:      int code;
                    828: {
                    829:   char buf[256];
                    830: 
                    831:   switch (GET_CODE (x))
                    832:     {
                    833:     case PC:
                    834:       if (flag_pic)
                    835:        putc ('.', file);
                    836:       else
                    837:        abort ();
                    838:       break;
                    839: 
                    840:     case SYMBOL_REF:
                    841:     case LABEL_REF:
                    842:       if (GET_CODE (x) == SYMBOL_REF)
                    843:        assemble_name (file, XSTR (x, 0));
                    844:       else
                    845:        {
                    846:          ASM_GENERATE_INTERNAL_LABEL (buf, "L",
                    847:                                       CODE_LABEL_NUMBER (XEXP (x, 0)));
                    848:          assemble_name (asm_out_file, buf);
                    849:        }
                    850: 
                    851:       if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
                    852:        fprintf (file, "@GOTOFF(%%ebx)");
                    853:       else if (code == 'P')
                    854:        fprintf (file, "@PLT");
                    855:       else if (GET_CODE (x) == LABEL_REF || ! SYMBOL_REF_FLAG (x))
                    856:        fprintf (file, "@GOT");
                    857:       else
                    858:        fprintf (file, "@GOTOFF");
                    859: 
                    860:       break;
                    861: 
                    862:     case CODE_LABEL:
                    863:       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
                    864:       assemble_name (asm_out_file, buf);
                    865:       break;
                    866: 
                    867:     case CONST_INT:
                    868:       fprintf (file, "%d", INTVAL (x));
                    869:       break;
                    870: 
                    871:     case CONST:
                    872:       /* This used to output parentheses around the expression,
                    873:         but that does not work on the 386 (either ATT or BSD assembler).  */
                    874:       output_pic_addr_const (file, XEXP (x, 0), code);
                    875:       break;
                    876: 
                    877:     case CONST_DOUBLE:
                    878:       if (GET_MODE (x) == VOIDmode)
                    879:        {
                    880:          /* We can use %d if the number is <32 bits and positive.  */
                    881:          if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
                    882:            fprintf (file, "0x%x%08x",
                    883:                     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
                    884:          else
                    885:            fprintf (file, "%d", CONST_DOUBLE_LOW (x));
                    886:        }
                    887:       else
                    888:        /* We can't handle floating point constants;
                    889:           PRINT_OPERAND must handle them.  */
                    890:        output_operand_lossage ("floating constant misused");
                    891:       break;
                    892: 
                    893:     case PLUS:
                    894:       /* Some assemblers need integer constants to appear last (eg masm).  */
                    895:       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
                    896:        {
                    897:          output_pic_addr_const (file, XEXP (x, 1), code);
                    898:          if (INTVAL (XEXP (x, 0)) >= 0)
                    899:            fprintf (file, "+");
                    900:          output_pic_addr_const (file, XEXP (x, 0), code);
                    901:        }
                    902:       else
                    903:        {
                    904:          output_pic_addr_const (file, XEXP (x, 0), code);
                    905:          if (INTVAL (XEXP (x, 1)) >= 0)
                    906:            fprintf (file, "+");
                    907:          output_pic_addr_const (file, XEXP (x, 1), code);
                    908:        }
                    909:       break;
                    910: 
                    911:     case MINUS:
                    912:       output_pic_addr_const (file, XEXP (x, 0), code);
                    913:       fprintf (file, "-");
                    914:       output_pic_addr_const (file, XEXP (x, 1), code);
                    915:       break;
                    916: 
                    917:     default:
                    918:       output_operand_lossage ("invalid expression as operand");
                    919:     }
                    920: }
                    921: 
                    922: /* Print the name of a register based on its machine mode and number.
                    923:    If CODE is 'w', pretend the mode is HImode.
                    924:    If CODE is 'b', pretend the mode is QImode.
                    925:    If CODE is 'k', pretend the mode is SImode.
                    926:    If CODE is 'h', pretend the reg is the `high' byte register.
                    927:    If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */
                    928: 
                    929: #define PRINT_REG(X, CODE, FILE) \
                    930:   do { if (REGNO (X) == ARG_POINTER_REGNUM)            \
                    931:         abort ();                                      \
                    932:        fprintf (FILE, "%s", RP);                       \
                    933:        switch ((CODE == 'w' ? 2                        \
                    934:                : CODE == 'b' ? 1                       \
                    935:                : CODE == 'k' ? 4                       \
                    936:                : CODE == 'y' ? 3                       \
                    937:                : CODE == 'h' ? 0                       \
                    938:                : GET_MODE_SIZE (GET_MODE (X))))        \
                    939:         {                                              \
                    940:         case 3:                                        \
                    941:           if (STACK_TOP_P (X))                         \
                    942:             {                                          \
                    943:               fputs ("st(0)", FILE);                   \
                    944:               break;                                   \
                    945:             }                                          \
                    946:         case 4:                                        \
                    947:         case 8:                                        \
                    948:           if (!FP_REG_P (X)) fputs ("e", FILE);        \
                    949:         case 2:                                        \
                    950:           fputs (hi_reg_name[REGNO (X)], FILE);        \
                    951:           break;                                       \
                    952:         case 1:                                        \
                    953:           fputs (qi_reg_name[REGNO (X)], FILE);        \
                    954:           break;                                       \
                    955:         case 0:                                        \
                    956:           fputs (qi_high_reg_name[REGNO (X)], FILE);   \
                    957:           break;                                       \
                    958:         }                                              \
                    959:      } while (0)
                    960: 
                    961: /* Meaning of CODE:
                    962:    f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
                    963:    D,L,W,B,Q,S -- print the opcode suffix for specified size of operand.
                    964:    R -- print the prefix for register names.
                    965:    z -- print the opcode suffix for the size of the current operand.
                    966:    * -- print a star (in certain assembler syntax)
                    967:    w -- print the operand as if it's a "word" (HImode) even if it isn't.
                    968:    c -- don't print special prefixes before constant operands.
                    969: */
                    970: 
                    971: void
                    972: print_operand (file, x, code)
                    973:      FILE *file;
                    974:      rtx x;
                    975:      int code;
                    976: {
                    977:   if (code)
                    978:     {
                    979:       switch (code)
                    980:        {
                    981:        case '*':
                    982:          if (USE_STAR)
                    983:            putc ('*', file);
                    984:          return;
                    985: 
                    986:        case 'L':
                    987:          PUT_OP_SIZE (code, 'l', file);
                    988:          return;
                    989: 
                    990:        case 'W':
                    991:          PUT_OP_SIZE (code, 'w', file);
                    992:          return;
                    993: 
                    994:        case 'B':
                    995:          PUT_OP_SIZE (code, 'b', file);
                    996:          return;
                    997: 
                    998:        case 'Q':
                    999:          PUT_OP_SIZE (code, 'l', file);
                   1000:          return;
                   1001: 
                   1002:        case 'S':
                   1003:          PUT_OP_SIZE (code, 's', file);
                   1004:          return;
                   1005: 
                   1006:        case 'z':
                   1007:          /* 387 opcodes don't get size suffixes if the operands are
                   1008:             registers. */
                   1009: 
                   1010:          if (STACK_REG_P (x))
                   1011:            return;
                   1012: 
                   1013:          /* this is the size of op from size of operand */
                   1014:          switch (GET_MODE_SIZE (GET_MODE (x)))
                   1015:            {
                   1016:            case 1:
                   1017:              PUT_OP_SIZE ('B', 'b', file);
                   1018:              return;
                   1019: 
                   1020:            case 2:
                   1021:              PUT_OP_SIZE ('W', 'w', file);
                   1022:              return;
                   1023: 
                   1024:            case 4:
                   1025:              if (GET_MODE (x) == SFmode)
                   1026:                {
                   1027:                  PUT_OP_SIZE ('S', 's', file);
                   1028:                  return;
                   1029:                }
                   1030:              else
                   1031:                PUT_OP_SIZE ('L', 'l', file);
                   1032:              return;
                   1033: 
                   1034:            case 8:
                   1035:              if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
1.1.1.3 ! root     1036:                {
        !          1037: #ifdef GAS_MNEMONICS
        !          1038:                  PUT_OP_SIZE ('Q', 'q', file);
        !          1039:                  return;
        !          1040: #else
        !          1041:                  PUT_OP_SIZE ('Q', 'l', file); /* Fall through */
        !          1042: #endif
        !          1043:                }
1.1       root     1044: 
                   1045:              PUT_OP_SIZE ('Q', 'l', file);
                   1046:              return;
                   1047:            }
1.1.1.3 ! root     1048: 
        !          1049:        case 'b':
        !          1050:        case 'w':
        !          1051:        case 'k':
        !          1052:        case 'h':
        !          1053:        case 'y':
        !          1054:        case 'P':
        !          1055:          break;
        !          1056: 
        !          1057:        default:
        !          1058:          abort ();
1.1       root     1059:        }
                   1060:     }
                   1061:   if (GET_CODE (x) == REG)
                   1062:     {
                   1063:       PRINT_REG (x, code, file);
                   1064:     }
                   1065:   else if (GET_CODE (x) == MEM)
                   1066:     {
                   1067:       PRINT_PTR (x, file);
                   1068:       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
                   1069:        {
                   1070:          if (flag_pic)
                   1071:            output_pic_addr_const (file, XEXP (x, 0), code);
                   1072:          else
                   1073:            output_addr_const (file, XEXP (x, 0));
                   1074:        }
                   1075:       else
                   1076:        output_address (XEXP (x, 0));
                   1077:     }
                   1078:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
                   1079:     {
                   1080:       union { double d; int i[2]; } u;
                   1081:       union { float f; int i; } u1;
                   1082:       u.i[0] = CONST_DOUBLE_LOW (x);
                   1083:       u.i[1] = CONST_DOUBLE_HIGH (x);
                   1084:       u1.f = u.d;
1.1.1.3 ! root     1085:       PRINT_IMMED_PREFIX (file);
        !          1086:       fprintf (file, "0x%x", u1.i);
1.1       root     1087:     }
                   1088:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
                   1089:     {
                   1090:       union { double d; int i[2]; } u;
                   1091:       u.i[0] = CONST_DOUBLE_LOW (x);
                   1092:       u.i[1] = CONST_DOUBLE_HIGH (x);
                   1093:       fprintf (file, "%.22e", u.d);
                   1094:     }
                   1095:   else 
                   1096:     {
1.1.1.3 ! root     1097:       if (code != 'P')
1.1       root     1098:        {
1.1.1.3 ! root     1099:          if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
1.1       root     1100:            PRINT_IMMED_PREFIX (file);
                   1101:          else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF
                   1102:                   || GET_CODE (x) == LABEL_REF)
                   1103:            PRINT_OFFSET_PREFIX (file);
                   1104:        }
                   1105:       if (flag_pic)
                   1106:        output_pic_addr_const (file, x, code);
                   1107:       else
                   1108:        output_addr_const (file, x);
                   1109:     }
                   1110: }
                   1111: 
                   1112: /* Print a memory operand whose address is ADDR.  */
                   1113: 
                   1114: void
                   1115: print_operand_address (file, addr)
                   1116:      FILE *file;
                   1117:      register rtx addr;
                   1118: {
                   1119:   register rtx reg1, reg2, breg, ireg;
                   1120:   rtx offset;
                   1121: 
                   1122:   switch (GET_CODE (addr))
                   1123:     {
                   1124:     case REG:
                   1125:       ADDR_BEG (file);
                   1126:       fprintf (file, "%se", RP);
                   1127:       fputs (hi_reg_name[REGNO (addr)], file);
                   1128:       ADDR_END (file);
                   1129:       break;
                   1130: 
                   1131:     case PLUS:
                   1132:       reg1 = 0;
                   1133:       reg2 = 0;
                   1134:       ireg = 0;
                   1135:       breg = 0;
                   1136:       offset = 0;
                   1137:       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
                   1138:        {
                   1139:          offset = XEXP (addr, 0);
                   1140:          addr = XEXP (addr, 1);
                   1141:        }
                   1142:       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
                   1143:        {
                   1144:          offset = XEXP (addr, 1);
                   1145:          addr = XEXP (addr, 0);
                   1146:        }
                   1147:       if (GET_CODE (addr) != PLUS) ;
                   1148:       else if (GET_CODE (XEXP (addr, 0)) == MULT)
                   1149:        {
                   1150:          reg1 = XEXP (addr, 0);
                   1151:          addr = XEXP (addr, 1);
                   1152:        }
                   1153:       else if (GET_CODE (XEXP (addr, 1)) == MULT)
                   1154:        {
                   1155:          reg1 = XEXP (addr, 1);
                   1156:          addr = XEXP (addr, 0);
                   1157:        }
                   1158:       else if (GET_CODE (XEXP (addr, 0)) == REG)
                   1159:        {
                   1160:          reg1 = XEXP (addr, 0);
                   1161:          addr = XEXP (addr, 1);
                   1162:        }
                   1163:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                   1164:        {
                   1165:          reg1 = XEXP (addr, 1);
                   1166:          addr = XEXP (addr, 0);
                   1167:        }
                   1168:       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
                   1169:        {
                   1170:          if (reg1 == 0) reg1 = addr;
                   1171:          else reg2 = addr;
                   1172:          addr = 0;
                   1173:        }
                   1174:       if (offset != 0)
                   1175:        {
                   1176:          if (addr != 0) abort ();
                   1177:          addr = offset;
                   1178:        }
                   1179:       if ((reg1 && GET_CODE (reg1) == MULT)
                   1180:          || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
                   1181:        {
                   1182:          breg = reg2;
                   1183:          ireg = reg1;
                   1184:        }
                   1185:       else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
                   1186:        {
                   1187:          breg = reg1;
                   1188:          ireg = reg2;
                   1189:        }
                   1190: 
                   1191:       if (ireg != 0 || breg != 0)
                   1192:        {
                   1193:          int scale = 1;
                   1194: 
                   1195:          if (addr != 0)
                   1196:            {
                   1197:              if (GET_CODE (addr) == LABEL_REF)
                   1198:                output_asm_label (addr);
                   1199:              else
                   1200:                {
                   1201:                  if (flag_pic)
                   1202:                    output_pic_addr_const (file, addr, 0);
                   1203:                  else
                   1204:                    output_addr_const (file, addr);
                   1205:                }
                   1206:            }
                   1207: 
                   1208:          if (ireg != 0 && GET_CODE (ireg) == MULT)
                   1209:            {
                   1210:              scale = INTVAL (XEXP (ireg, 1));
                   1211:              ireg = XEXP (ireg, 0);
                   1212:            }
                   1213: 
                   1214:          /* The stack pointer can only appear as a base register,
                   1215:             never an index register, so exchange the regs if it is wrong. */
                   1216: 
                   1217:          if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM)
                   1218:            {
                   1219:              rtx tmp;
                   1220: 
                   1221:              tmp = breg;
                   1222:              breg = ireg;
                   1223:              ireg = tmp;
                   1224:            }
                   1225: 
                   1226:          /* output breg+ireg*scale */
                   1227:          PRINT_B_I_S (breg, ireg, scale, file);
                   1228:          break;
                   1229:        }
                   1230: 
                   1231:     case MULT:
                   1232:       {
                   1233:        int scale;
                   1234:        if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
                   1235:          {
                   1236:            scale = INTVAL (XEXP (addr, 0));
                   1237:            ireg = XEXP (addr, 1);
                   1238:          }
                   1239:        else
                   1240:          {
                   1241:            scale = INTVAL (XEXP (addr, 1));
                   1242:            ireg = XEXP (addr, 0);
                   1243:          }
                   1244:        output_addr_const (file, const0_rtx);
                   1245:        PRINT_B_I_S ((rtx) 0, ireg, scale, file);
                   1246:       }
                   1247:       break;
                   1248: 
                   1249:     default:
                   1250:       if (GET_CODE (addr) == CONST_INT
                   1251:          && INTVAL (addr) < 0x8000
                   1252:          && INTVAL (addr) >= -0x8000)
                   1253:        fprintf (file, "%d", INTVAL (addr));
                   1254:       else
                   1255:        {
                   1256:          if (flag_pic)
                   1257:            output_pic_addr_const (file, addr, 0);
                   1258:          else
                   1259:            output_addr_const (file, addr);
                   1260:        }
                   1261:     }
                   1262: }
                   1263: 
                   1264: /* Set the cc_status for the results of an insn whose pattern is EXP.
                   1265:    On the 80386, we assume that only test and compare insns, as well
                   1266:    as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT,
                   1267:    ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
                   1268:    Also, we assume that jumps, moves and sCOND don't affect the condition
                   1269:    codes.  All else clobbers the condition codes, by assumption.
                   1270: 
                   1271:    We assume that ALL integer add, minus, etc. instructions effect the
                   1272:    condition codes.  This MUST be consistent with i386.md.
                   1273: 
                   1274:    We don't record any float test or compare - the redundant test &
                   1275:    compare check in final.c does not handle stack-like regs correctly. */
                   1276: 
                   1277: void
                   1278: notice_update_cc (exp)
                   1279:      rtx exp;
                   1280: {
                   1281:   if (GET_CODE (exp) == SET)
                   1282:     {
                   1283:       /* Jumps do not alter the cc's.  */
                   1284:       if (SET_DEST (exp) == pc_rtx)
                   1285:        return;
                   1286:       /* Moving register or memory into a register:
                   1287:         it doesn't alter the cc's, but it might invalidate
                   1288:         the RTX's which we remember the cc's came from.
                   1289:         (Note that moving a constant 0 or 1 MAY set the cc's).  */
                   1290:       if (REG_P (SET_DEST (exp))
                   1291:          && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
                   1292:              || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
                   1293:        {
                   1294:          if (cc_status.value1
                   1295:              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
                   1296:            cc_status.value1 = 0;
                   1297:          if (cc_status.value2
                   1298:              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
                   1299:            cc_status.value2 = 0;
                   1300:          return;
                   1301:        }
                   1302:       /* Moving register into memory doesn't alter the cc's.
                   1303:         It may invalidate the RTX's which we remember the cc's came from.  */
                   1304:       if (GET_CODE (SET_DEST (exp)) == MEM
                   1305:          && (REG_P (SET_SRC (exp))
                   1306:              || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
                   1307:        {
                   1308:          if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
                   1309:            cc_status.value1 = 0;
                   1310:          if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
                   1311:            cc_status.value2 = 0;
                   1312:          return;
                   1313:        }
                   1314:       /* Function calls clobber the cc's.  */
                   1315:       else if (GET_CODE (SET_SRC (exp)) == CALL)
                   1316:        {
                   1317:          CC_STATUS_INIT;
                   1318:          return;
                   1319:        }
                   1320:       /* Tests and compares set the cc's in predictable ways.  */
                   1321:       else if (SET_DEST (exp) == cc0_rtx)
                   1322:        {
                   1323:          CC_STATUS_INIT;
                   1324:          cc_status.value1 = SET_SRC (exp);
                   1325:          return;
                   1326:        }
                   1327:       /* Certain instructions effect the condition codes. */
                   1328:       else if (GET_MODE (SET_SRC (exp)) == SImode
                   1329:               || GET_MODE (SET_SRC (exp)) == HImode
                   1330:               || GET_MODE (SET_SRC (exp)) == QImode)
                   1331:        switch (GET_CODE (SET_SRC (exp)))
                   1332:          {
                   1333:          case ASHIFTRT: case LSHIFTRT:
                   1334:          case ASHIFT: case LSHIFT:
                   1335:            /* Shifts on the 386 don't set the condition codes if the
                   1336:               shift count is zero. */
                   1337:            if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
                   1338:              {
                   1339:                CC_STATUS_INIT;
                   1340:                break;
                   1341:              }
                   1342:            /* We assume that the CONST_INT is non-zero (this rtx would
                   1343:               have been deleted if it were zero. */
                   1344: 
                   1345:          case PLUS: case MINUS: case NEG:
                   1346:          case AND: case IOR: case XOR:
                   1347:            cc_status.flags = CC_NO_OVERFLOW;
                   1348:            cc_status.value1 = SET_SRC (exp);
                   1349:            cc_status.value2 = SET_DEST (exp);
                   1350:            break;
                   1351: 
                   1352:          default:
                   1353:            CC_STATUS_INIT;
                   1354:          }
                   1355:       else
                   1356:        {
                   1357:          CC_STATUS_INIT;
                   1358:        }
                   1359:     }
                   1360:   else if (GET_CODE (exp) == PARALLEL
                   1361:           && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
                   1362:     {
                   1363:       if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
                   1364:        return;
                   1365:       if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
                   1366:        {
                   1367:          CC_STATUS_INIT;
                   1368:          if (! stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
                   1369:            cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
1.1.1.3 ! root     1370: 
        !          1371:          cc_status.flags |= CC_IN_80387;
1.1       root     1372:          return;
                   1373:        }
                   1374:       CC_STATUS_INIT;
                   1375:     }
                   1376:   else
                   1377:     {
                   1378:       CC_STATUS_INIT;
                   1379:     }
                   1380: }
                   1381: 
                   1382: /* Split one or more DImode RTL references into pairs of SImode
                   1383:    references.  The RTL can be REG, offsettable MEM, integer constant, or
                   1384:    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
                   1385:    split and "num" is its length.  lo_half and hi_half are output arrays
                   1386:    that parallel "operands". */
                   1387: 
                   1388: void
                   1389: split_di (operands, num, lo_half, hi_half)
                   1390:      rtx operands[];
                   1391:      int num;
                   1392:      rtx lo_half[], hi_half[];
                   1393: {
                   1394:   while (num--)
                   1395:     {
                   1396:       if (GET_CODE (operands[num]) == REG)
                   1397:        {
                   1398:          lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
                   1399:          hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
                   1400:        }
                   1401:       else if (CONSTANT_P (operands[num]))
                   1402:        {
                   1403:          split_double (operands[num], &lo_half[num], &hi_half[num]);
                   1404:        }
                   1405:       else if (offsettable_memref_p (operands[num]))
                   1406:        {
                   1407:          lo_half[num] = operands[num];
                   1408:          hi_half[num] = adj_offsettable_operand (operands[num], 4);
                   1409:        }
                   1410:       else
                   1411:        abort();
                   1412:     }
                   1413: }
                   1414: 
                   1415: /* Return 1 if this is a valid binary operation on a 387.
                   1416:    OP is the expression matched, and MODE is its mode. */
                   1417: 
                   1418: int
                   1419: binary_387_op (op, mode)
                   1420:     register rtx op;
                   1421:     enum machine_mode mode;
                   1422: {
                   1423:   if (mode != VOIDmode && mode != GET_MODE (op))
                   1424:     return 0;
                   1425: 
                   1426:   switch (GET_CODE (op))
                   1427:     {
                   1428:     case PLUS:
                   1429:     case MINUS:
                   1430:     case MULT:
                   1431:     case DIV:
                   1432:       return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
                   1433: 
                   1434:     default:
                   1435:       return 0;
                   1436:     }
                   1437: }
                   1438: 
                   1439: /* Return 1 if this is a valid conversion operation on a 387.
                   1440:    OP is the expression matched, and MODE is its mode. */
                   1441: 
                   1442: int
                   1443: convert_387_op (op, mode)
                   1444:     register rtx op;
                   1445:     enum machine_mode mode;
                   1446: {
                   1447:   if (mode != VOIDmode && mode != GET_MODE (op))
                   1448:     return 0;
                   1449: 
                   1450:   switch (GET_CODE (op))
                   1451:     {
                   1452:     case FLOAT:
                   1453:       return GET_MODE (XEXP (op, 0)) == SImode;
                   1454: 
                   1455:     case FLOAT_EXTEND:
                   1456:       return mode == DFmode && GET_MODE (XEXP (op, 0)) == SFmode;
                   1457: 
                   1458:     default:
                   1459:       return 0;
                   1460:     }
                   1461: }
                   1462: 
                   1463: /* Return 1 if this is a valid "float from int" operation on a 387.
                   1464:    OP is the expression matched, and MODE is its mode. */
                   1465: 
                   1466: int
                   1467: float_op (op, mode)
                   1468:     register rtx op;
                   1469:     enum machine_mode mode;
                   1470: {
                   1471:   if (mode != VOIDmode && mode != GET_MODE (op))
                   1472:     return 0;
                   1473: 
                   1474:   return GET_CODE (op) == FLOAT
                   1475:     && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
                   1476: }
                   1477: 
                   1478: /* Return 1 if this is a valid shift or rotate operation on a 386.
                   1479:    OP is the expression matched, and MODE is its mode. */
                   1480: 
                   1481: int
                   1482: shift_op (op, mode)
                   1483:     register rtx op;
                   1484:     enum machine_mode mode;
                   1485: {
                   1486:   rtx operand = XEXP (op, 0);
                   1487: 
                   1488:   if (mode != VOIDmode && mode != GET_MODE (op))
                   1489:     return 0;
                   1490: 
                   1491:   if (GET_MODE (operand) != GET_MODE (op)
                   1492:       || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT)
                   1493:     return 0;
                   1494: 
                   1495:   return (GET_CODE (op) == ASHIFT
                   1496:          || GET_CODE (op) == ASHIFTRT
                   1497:          || GET_CODE (op) == LSHIFTRT
                   1498:          || GET_CODE (op) == ROTATE
                   1499:          || GET_CODE (op) == ROTATERT);
                   1500: }
                   1501: 
                   1502: /* Output code to perform a 387 binary operation in INSN, one of PLUS,
                   1503:    MINUS, MULT or DIV.  OPERANDS are the insn operands, where operands[3]
                   1504:    is the expression of the binary operation.  The output may either be
                   1505:    emitted here, or returned to the caller, like all output_* functions.
                   1506: 
                   1507:    There is no guarantee that the operands are the same mode, as they
                   1508:    might be within FLOAT or FLOAT_EXTEND expressions. */
                   1509: 
                   1510: char *
                   1511: output_387_binary_op (insn, operands)
                   1512:      rtx insn;
                   1513:      rtx *operands;
                   1514: {
                   1515:   rtx temp;
                   1516:   char *base_op;
                   1517:   static char buf[100];
                   1518: 
                   1519:   switch (GET_CODE (operands[3]))
                   1520:     {
                   1521:     case PLUS:
                   1522:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   1523:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   1524:        base_op = "fiadd";
                   1525:       else
                   1526:        base_op = "fadd";
                   1527:       break;
                   1528: 
                   1529:     case MINUS:
                   1530:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   1531:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   1532:        base_op = "fisub";
                   1533:       else
                   1534:        base_op = "fsub";
                   1535:       break;
                   1536: 
                   1537:     case MULT:
                   1538:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   1539:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   1540:        base_op = "fimul";
                   1541:       else
                   1542:        base_op = "fmul";
                   1543:       break;
                   1544: 
                   1545:     case DIV:
                   1546:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
                   1547:          || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
                   1548:        base_op = "fidiv";
                   1549:       else
                   1550:        base_op = "fdiv";
                   1551:       break;
                   1552: 
                   1553:     default:
                   1554:       abort ();
                   1555:     }
                   1556: 
                   1557:   strcpy (buf, base_op);
                   1558: 
                   1559:   switch (GET_CODE (operands[3]))
                   1560:     {
                   1561:     case MULT:
                   1562:     case PLUS:
                   1563:       if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
                   1564:        {
                   1565:          temp = operands[2];
                   1566:          operands[2] = operands[1];
                   1567:          operands[1] = temp;
                   1568:        }
                   1569: 
                   1570:       if (GET_CODE (operands[2]) == MEM)
                   1571:        return strcat (buf, AS1 (%z2,%2));
                   1572: 
                   1573:       if (NON_STACK_REG_P (operands[1]))
                   1574:        {
                   1575:          output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
                   1576:          RET;
                   1577:        }
                   1578:       else if (NON_STACK_REG_P (operands[2]))
                   1579:        {
                   1580:          output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
                   1581:          RET;
                   1582:        }
                   1583: 
                   1584:       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
                   1585:        return strcat (buf, AS2 (p,%2,%0));
                   1586: 
                   1587:       if (STACK_TOP_P (operands[0]))
                   1588:        return strcat (buf, AS2 (,%y2,%0));
                   1589:       else
                   1590:        return strcat (buf, AS2 (,%2,%0));
                   1591: 
                   1592:     case MINUS:
                   1593:     case DIV:
                   1594:       if (GET_CODE (operands[1]) == MEM)
                   1595:        return strcat (buf, AS1 (r%z1,%1));
                   1596: 
                   1597:       if (GET_CODE (operands[2]) == MEM)
                   1598:        return strcat (buf, AS1 (%z2,%2));
                   1599: 
                   1600:       if (NON_STACK_REG_P (operands[1]))
                   1601:        {
                   1602:          output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1)));
                   1603:          RET;
                   1604:        }
                   1605:       else if (NON_STACK_REG_P (operands[2]))
                   1606:        {
                   1607:          output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
                   1608:          RET;
                   1609:        }
                   1610: 
                   1611:       if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
                   1612:        abort ();
                   1613: 
                   1614:       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
                   1615:        return strcat (buf, AS2 (rp,%2,%0));
                   1616: 
                   1617:       if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
                   1618:        return strcat (buf, AS2 (p,%1,%0));
                   1619: 
                   1620:       if (STACK_TOP_P (operands[0]))
                   1621:        {
                   1622:          if (STACK_TOP_P (operands[1]))
                   1623:            return strcat (buf, AS2 (,%y2,%0));
                   1624:          else
                   1625:            return strcat (buf, AS2 (r,%y1,%0));
                   1626:        }
                   1627:       else if (STACK_TOP_P (operands[1]))
                   1628:        return strcat (buf, AS2 (,%1,%0));
                   1629:       else
                   1630:        return strcat (buf, AS2 (r,%2,%0));
                   1631: 
                   1632:     default:
                   1633:       abort ();
                   1634:     }
                   1635: }
                   1636: 
                   1637: /* Output code for INSN to convert a float to a signed int.  OPERANDS
                   1638:    are the insn operands.  The output may be SFmode or DFmode and the
                   1639:    input operand may be SImode or DImode.  As a special case, make sure
                   1640:    that the 387 stack top dies if the output mode is DImode, because the
                   1641:    hardware requires this.  */
                   1642: 
                   1643: char *
                   1644: output_fix_trunc (insn, operands)
                   1645:      rtx insn;
                   1646:      rtx *operands;
                   1647: {
                   1648:   int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
                   1649:   rtx xops[6];
                   1650: 
                   1651:   if (! STACK_TOP_P (operands[1]) ||
                   1652:       (GET_MODE (operands[0]) == DImode && ! stack_top_dies))
                   1653:     abort ();
                   1654: 
                   1655:   xops[0] = stack_pointer_rtx;
                   1656:   xops[1] = AT_SP (SImode);
                   1657:   xops[2] = adj_offsettable_operand (xops[1], 2);
                   1658:   xops[3] = gen_rtx (CONST_INT, VOIDmode, 4);
                   1659:   xops[4] = gen_rtx (CONST_INT, VOIDmode, 0xc00);
                   1660:   xops[5] = operands[2];
                   1661: 
                   1662:   output_asm_insn (AS2 (sub%L0,%3,%0), xops);
                   1663:   output_asm_insn (AS1 (fnstc%W5,%1), xops);
                   1664:   output_asm_insn (AS2 (mov%W5,%1,%5), xops);
                   1665:   output_asm_insn (AS2 (or%W5,%4,%5), xops);
                   1666:   output_asm_insn (AS2 (mov%W5,%5,%2), xops);
                   1667:   output_asm_insn (AS1 (fldc%W5,%2), xops);
                   1668: 
                   1669:   if (NON_STACK_REG_P (operands[0]))
                   1670:     output_to_reg (operands[0], stack_top_dies);
                   1671:   else if (GET_CODE (operands[0]) == MEM)
                   1672:     {
                   1673:       /* If frame pointer elimination is being done, the MEM reference
                   1674:         might be an index off of the stack pointer.  In that case,
                   1675:         since we have already adjusted %esp above, adjust the operand
                   1676:         address so it points where it should. */
                   1677: 
                   1678:       if (! frame_pointer_needed
                   1679:          && reg_mentioned_p (stack_pointer_rtx, operands[0]))
                   1680:        operands[0] = adj_offsettable_operand (operands[0], 4);
                   1681: 
                   1682:       if (stack_top_dies)
                   1683:        output_asm_insn (AS1 (fistp%z0,%0), operands);
                   1684:       else
                   1685:        output_asm_insn (AS1 (fist%z0,%0), operands);
                   1686:     }
                   1687:   else
                   1688:     abort ();
                   1689: 
                   1690:   output_asm_insn (AS1 (fldc%W5,%1), xops);
                   1691:   output_asm_insn (AS2 (add%L0,%3,%0), xops);
                   1692: 
                   1693:   RET;
                   1694: }
                   1695: 
                   1696: /* Output code for INSN to compare OPERANDS.  The two operands might
                   1697:    not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
1.1.1.3 ! root     1698:    expression.  If the compare is in mode CCFPEQmode, use an opcode that
        !          1699:    will not fault if a qNaN is present. */
1.1       root     1700: 
                   1701: char *
                   1702: output_float_compare (insn, operands)
                   1703:      rtx insn;
                   1704:      rtx *operands;
                   1705: {
                   1706:   int stack_top_dies;
1.1.1.3 ! root     1707:   rtx body = XVECEXP (PATTERN (insn), 0, 0);
        !          1708:   int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
1.1       root     1709: 
                   1710:   if (! STACK_TOP_P (operands[0]))
                   1711:     abort ();
                   1712: 
                   1713:   stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
                   1714: 
                   1715:   if (STACK_REG_P (operands[1])
                   1716:       && stack_top_dies
                   1717:       && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))
                   1718:       && REGNO (operands[1]) != FIRST_STACK_REG)
                   1719:     {
                   1720:       /* If both the top of the 387 stack dies, and the other operand
                   1721:         is also a stack register that dies, then this must be a
                   1722:         `fcompp' float compare */
                   1723: 
1.1.1.3 ! root     1724:       if (unordered_compare)
        !          1725:        output_asm_insn ("fucompp", operands);
        !          1726:       else
        !          1727:        output_asm_insn ("fcompp", operands);
1.1       root     1728:     }
                   1729:   else
                   1730:     {
                   1731:       static char buf[100];
                   1732: 
1.1.1.3 ! root     1733:       /* Decide if this is the integer or float compare opcode, or the
        !          1734:         unordered float compare. */
1.1       root     1735: 
1.1.1.3 ! root     1736:       if (unordered_compare)
        !          1737:        strcpy (buf, "fucom");
        !          1738:       else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
1.1       root     1739:        strcpy (buf, "fcom");
                   1740:       else
                   1741:        strcpy (buf, "ficom");
                   1742: 
                   1743:       /* Modify the opcode if the 387 stack is to be popped. */
                   1744: 
                   1745:       if (stack_top_dies)
                   1746:        strcat (buf, "p");
                   1747: 
                   1748:       if (NON_STACK_REG_P (operands[1]))
                   1749:        output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
                   1750:       else
                   1751:         output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
                   1752:     }
                   1753: 
                   1754:   /* Now retrieve the condition code. */
                   1755: 
1.1.1.3 ! root     1756:   return output_fp_cc0_set (insn);
        !          1757: }
        !          1758: 
        !          1759: /* Output opcodes to transfer the results of FP compare or test INSN
        !          1760:    from the FPU to the CPU flags.  If TARGET_IEEE_FP, ensure that if the
        !          1761:    result of the compare or test is unordered, no comparison operator
        !          1762:    succeeds except NE.  Return an output template, if any.  */
        !          1763: 
        !          1764: char *
        !          1765: output_fp_cc0_set (insn)
        !          1766:      rtx insn;
        !          1767: {
        !          1768:   rtx xops[3];
        !          1769:   rtx unordered_label;
        !          1770:   rtx next;
        !          1771:   enum rtx_code code;
        !          1772: 
        !          1773:   xops[0] = gen_rtx (REG, HImode, 0);
        !          1774:   output_asm_insn (AS1 (fnsts%W0,%0), xops);
        !          1775: 
        !          1776:   if (! TARGET_IEEE_FP)
        !          1777:     return "sahf";
        !          1778: 
        !          1779:   next = next_cc0_user (insn);
1.1       root     1780: 
1.1.1.3 ! root     1781:   if (GET_CODE (next) == JUMP_INSN
        !          1782:       && GET_CODE (PATTERN (next)) == SET
        !          1783:       && SET_DEST (PATTERN (next)) == pc_rtx
        !          1784:       && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
        !          1785:     {
        !          1786:       code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
        !          1787:     }
        !          1788:   else if (GET_CODE (PATTERN (next)) == SET)
        !          1789:     {
        !          1790:       code = GET_CODE (SET_SRC (PATTERN (next)));
        !          1791:     }
        !          1792:   else
        !          1793:     abort ();
        !          1794: 
        !          1795:   xops[0] = gen_rtx (REG, QImode, 0);
        !          1796: 
        !          1797:   switch (code)
        !          1798:     {
        !          1799:     case GT:
        !          1800:       xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
        !          1801:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
        !          1802:       /* je label */
        !          1803:       break;
        !          1804: 
        !          1805:     case LT:
        !          1806:       xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
        !          1807:       xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x01);
        !          1808:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
        !          1809:       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
        !          1810:       /* je label */
        !          1811:       break;
        !          1812: 
        !          1813:     case GE:
        !          1814:       xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x05);
        !          1815:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
        !          1816:       /* je label */
        !          1817:       break;
        !          1818: 
        !          1819:     case LE:
        !          1820:       xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
        !          1821:       xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
        !          1822:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
        !          1823:       output_asm_insn (AS1 (dec%B0,%h0), xops);
        !          1824:       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
        !          1825:       /* jb label */
        !          1826:       break;
        !          1827: 
        !          1828:     case EQ:
        !          1829:       xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
        !          1830:       xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
        !          1831:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
        !          1832:       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
        !          1833:       /* je label */
        !          1834:       break;
        !          1835: 
        !          1836:     case NE:
        !          1837:       xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x44);
        !          1838:       xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
        !          1839:       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
        !          1840:       output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
        !          1841:       /* jne label */
        !          1842:       break;
        !          1843: 
        !          1844:     case GTU:
        !          1845:     case LTU:
        !          1846:     case GEU:
        !          1847:     case LEU:
        !          1848:     default:
        !          1849:       abort ();
        !          1850:     }
        !          1851:   RET;
1.1       root     1852: }
                   1853: 
                   1854: #ifdef HANDLE_PRAGMA
                   1855: 
                   1856: /* When structure field packing is in effect, this variable is the
                   1857:    number of bits to use as the maximum alignment.  When packing is not
                   1858:    in effect, this is zero. */
                   1859: 
                   1860: int maximum_field_alignment = 0;
                   1861: 
                   1862: /* Handle a pragma directive.  HANDLE_PRAGMA conspires to parse the
                   1863:    input following #pragma into tokens based on yylex.  TOKEN is the
                   1864:    current token, and STRING is its printable form.  */
                   1865: 
                   1866: void
                   1867: handle_pragma_token (string, token)
                   1868:      char *string;
                   1869:      tree token;
                   1870: {
                   1871:   static enum pragma_state
                   1872:     {
                   1873:       ps_start,
                   1874:       ps_done,
                   1875:       ps_bad,
                   1876:       ps_weak,
                   1877:       ps_name,
                   1878:       ps_equals,
                   1879:       ps_value,
                   1880:       ps_pack,
                   1881:       ps_left,
                   1882:       ps_align,
                   1883:       ps_right
                   1884:       } state = ps_start, type;
                   1885:   static char *name;
                   1886:   static char *value;
                   1887:   static int align;
                   1888: 
                   1889:   if (string == 0)
                   1890:     {
                   1891:       if (type == ps_pack)
                   1892:        {
                   1893:          if (state == ps_right)
                   1894:            maximum_field_alignment = align * 8;
                   1895:          else
                   1896:            warning ("ignoring malformed #pragma pack( [ 1 | 2 | 4 ] )");
                   1897:        }
                   1898: #ifdef WEAK_ASM_OP
                   1899:       else if (type == ps_weak)
                   1900:        {
                   1901:          if (state == ps_name || state == ps_value)
                   1902:            {
                   1903:              fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
                   1904:              ASM_OUTPUT_LABELREF (asm_out_file, name);
                   1905:              fputc ('\n', asm_out_file);
                   1906:              if (state == ps_value)
                   1907:                {
1.1.1.3 ! root     1908:                  fprintf (asm_out_file, "\t%s\t", SET_ASM_OP);
1.1       root     1909:                  ASM_OUTPUT_LABELREF (asm_out_file, name);
                   1910:                  fputc (',', asm_out_file);
                   1911:                  ASM_OUTPUT_LABELREF (asm_out_file, value);
                   1912:                  fputc ('\n', asm_out_file);
                   1913:                }
                   1914:            }
                   1915:          else if (! (state == ps_done || state == ps_start))
                   1916:            warning ("ignoring malformed #pragma weak symbol [=value]");
                   1917:        }
                   1918: #endif /* WEAK_ASM_OP */
                   1919: 
                   1920:       type = state = ps_start;
                   1921:       return;
                   1922:     }
                   1923: 
                   1924:   switch (state)
                   1925:     {
                   1926:     case ps_start:
                   1927:       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
                   1928:        {
                   1929:          if (strcmp (IDENTIFIER_POINTER (token), "pack") == 0)
                   1930:            type = state = ps_pack;
                   1931: #ifdef WEAK_ASM_OP
                   1932:          else if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
                   1933:            type = state = ps_weak;
                   1934: #endif
                   1935:          else
                   1936:            type = state = ps_done;
                   1937:        }
                   1938:       else
                   1939:        type = state = ps_done;
                   1940:       break;
                   1941: 
                   1942: #ifdef WEAK_ASM_OP
                   1943:     case ps_weak:
                   1944:       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
                   1945:        {
                   1946:          name = IDENTIFIER_POINTER (token);
                   1947:          state = ps_name;
                   1948:        }
                   1949:       else
                   1950:        state = ps_bad;
                   1951:       break;
                   1952: 
                   1953:     case ps_name:
                   1954:       state = (strcmp (string, "=") ? ps_bad : ps_equals);
                   1955:       break;
                   1956: 
                   1957:     case ps_equals:
                   1958:       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
                   1959:        {
                   1960:          value = IDENTIFIER_POINTER (token);
                   1961:          state = ps_value;
                   1962:        }
                   1963:       else
                   1964:        state = ps_bad;
                   1965:       break;
                   1966: 
                   1967:     case ps_value:
                   1968:       state = ps_bad;
                   1969:       break;
                   1970: #endif /* WEAK_ASM_OP */
                   1971: 
                   1972:     case ps_pack:
                   1973:       if (strcmp (string, "(") == 0)
                   1974:        state = ps_left;
                   1975:       else
                   1976:        state = ps_bad;
                   1977:       break;
                   1978: 
                   1979:     case ps_left:
                   1980:       if (token && TREE_CODE (token) == INTEGER_CST
                   1981:          && TREE_INT_CST_HIGH (token) == 0)
                   1982:        switch (TREE_INT_CST_LOW (token))
                   1983:          {
                   1984:          case 1:
                   1985:          case 2:
                   1986:          case 4:
                   1987:            align = TREE_INT_CST_LOW (token);
                   1988:            state = ps_align;
                   1989:            break;
                   1990: 
                   1991:          default:
                   1992:            state = ps_bad;
                   1993:          }
                   1994:       else if (! token && strcmp (string, ")") == 0)
                   1995:        {
                   1996:          align = 0;
                   1997:          state = ps_right;
                   1998:        }
                   1999:       else
                   2000:        state = ps_bad;
                   2001:       break;
                   2002: 
                   2003:     case ps_align:
                   2004:       if (strcmp (string, ")") == 0)
                   2005:        state = ps_right;
                   2006:       else
                   2007:        state = ps_bad;
                   2008:       break;
                   2009: 
                   2010:     case ps_right:
                   2011:       state = ps_bad;
                   2012:       break;
                   2013: 
                   2014:     case ps_bad:
                   2015:     case ps_done:
                   2016:       break;
                   2017: 
                   2018:     default:
                   2019:       abort ();
                   2020:     }
                   2021: }
                   2022: #endif /* HANDLE_PRAGMA */

unix.superglobalmegacorp.com

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