Annotation of GNUtools/cc/config/i386/i386.c, revision 1.1

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

unix.superglobalmegacorp.com

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