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

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

unix.superglobalmegacorp.com

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