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

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

unix.superglobalmegacorp.com

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