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

1.1     ! root        1: /* Subroutines for insn-output.c for Intel 80386.
        !             2:    Copyright (C) 1988 Free Software Foundation, Inc.
        !             3: 
        !             4: This file is part of GNU CC.
        !             5: 
        !             6: GNU CC is free software; you can redistribute it and/or modify
        !             7: it under the terms of the GNU General Public License as published by
        !             8: the Free Software Foundation; either version 1, 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: #ifndef FILE
        !            21: #include <stdio.h>
        !            22: #endif
        !            23: 
        !            24: #define FP_TOP (gen_rtx(REG, DFmode, FIRST_FLOAT_REG))
        !            25: 
        !            26: #define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx))
        !            27: #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
        !            28: 
        !            29: #define RET return ""
        !            30: 
        !            31: /* #define RETCOM(X) fprintf (asm_out_file, "%sX fp_pop_level=%d\n", \
        !            32:                           COMMENT_BEGIN, fp_pop_level); RET */
        !            33: #define RETCOM(X) return ""
        !            34: 
        !            35: #define POP_ONE_FP     \
        !            36:   { /* fp_pop_level--; */      \
        !            37:     fprintf (asm_out_file, "\tfstp %sst (0)\n", RP); }
        !            38: 
        !            39: extern FILE *asm_out_file;
        !            40: static char *singlemove_string ();
        !            41: static void output_movf ();
        !            42: static void replace_float_constant ();
        !            43: static int mentions_fp_top ();
        !            44: static int call_top_dead_p ();
        !            45: static int fp_top_dead_p1 ();
        !            46: static rtx via_memory ();
        !            47: static void output_asm_insn_double_reg_op ();
        !            48: 
        !            49: /* All output functions must increment or decrement this to indicate
        !            50:    the net number of pops or pushes which they perform.  Note that it won't
        !            51:    necessarily balance with the optimize running, since we might have
        !            52:    two different calls with the same pop shared by cross jumping.
        !            53:    However on optimize the reg dead heuristic seems to work.  */
        !            54: 
        !            55: int fp_pop_level = 0;
        !            56: 
        !            57: static char *hi_reg_name[] = HI_REGISTER_NAMES;
        !            58: static char *qi_reg_name[] = QI_REGISTER_NAMES;
        !            59: 
        !            60: /* for fabs, fch, .. where the argument operand[1] must first be moved to
        !            61:   constraints  "=fm" "0" */
        !            62: 
        !            63: #define FP_CALL1(op)  \
        !            64:   { if (FP_REG_P (operands[0]))                \
        !            65:       return op;                       \
        !            66:     output_movf (FP_TOP, operands[1]); \
        !            67:     output_asm_insn (op, operands);    \
        !            68:     /* fp_pop_level--; */              \
        !            69:     return "fstp%z0 %0"; }
        !            70: 
        !            71: /* handle case of call where op0/op1 is "=mf" and opn is "mrf"
        !            72:    eg. fadd */
        !            73: #define FP_CALL(op, rev, n)  \
        !            74:   return fp_call_internal (op, rev, n, operands, insn);
        !            75: 
        !            76: static char *
        !            77: fp_call_internal (op, rev, n, operands, insn)
        !            78:      char *op;
        !            79:      char *rev;
        !            80:      int n;
        !            81:      rtx *operands;
        !            82:      rtx insn;
        !            83: {
        !            84:   if (!FP_REG_P (operands[0]))
        !            85:     {
        !            86:       /* Here destination is in memory
        !            87:         and source is in the fp stack.  */
        !            88:       output_movf (FP_TOP, operands[0]);
        !            89:       output_asm_insn_double_reg_op (op, rev, insn);
        !            90:       return "fstp%z0 %0";
        !            91:     }
        !            92: 
        !            93:   if (FP_REG_P (operands[n]))
        !            94:     {
        !            95:       rtx temp = operands[1];
        !            96:       char *tem1 = op;
        !            97:       operands[1] = operands[n];
        !            98:       op = rev;
        !            99:       operands[n] = temp;
        !           100:       rev = tem1;
        !           101:     }
        !           102: 
        !           103:   if (REG_P (operands[n]))
        !           104:     {
        !           105:       rtx xops[2];
        !           106:       via_memory (operands[n]);
        !           107:       operands[n] = AT_SP (GET_MODE (operands[n]));
        !           108:       xops[0] = stack_pointer_rtx;
        !           109:       xops[1] = gen_rtx (CONST_INT, VOIDmode,
        !           110:                         GET_MODE_SIZE (GET_MODE (operands[n])));
        !           111:       output_asm_insn (op, operands + n);
        !           112:       output_asm_insn (AS2 (add%L0,%1,%0), xops);
        !           113:     }
        !           114:   else
        !           115:     output_asm_insn (op, operands + n);
        !           116: 
        !           117:   RET;
        !           118: }
        !           119: 
        !           120: /* Output assembler code to perform insn OP
        !           121:    with two stack operands, and output on the stack.
        !           122: 
        !           123:    REV is the assembler insn that does the same thing but
        !           124:    effectively interchanges the meanings of the two arguments.
        !           125: 
        !           126:    Somewhat counterintuitively, the "first" operand was pushed last.
        !           127: 
        !           128:    The output replaces either the top-of-stack or both of the arguments,
        !           129:    depending on whether the other argument is wanted after this insn.  */
        !           130: 
        !           131: static void
        !           132: output_asm_insn_double_reg_op (op, rev, insn)
        !           133:      char *op;
        !           134:      char *rev;
        !           135:      rtx insn;
        !           136: {
        !           137:   fputc ('\t', asm_out_file);
        !           138:   if (top_dead_p (insn))
        !           139:     {
        !           140:       /* Here we want the "reversed" insn, fsubr or fdivr.
        !           141:         But there is an assembler bug in all 80386 assemblers
        !           142:         which exchanges the meanings of fsubr and fsub, and of fdivr and fdiv!
        !           143:         So use the "unreversed" opcode (which will assemble into
        !           144:         the "reversed" insn).  */
        !           145:       rev = op;
        !           146: 
        !           147:       while (*rev && *rev != '%')
        !           148:        fputc (*rev++, asm_out_file);
        !           149:       /* fp_pop_level--; */
        !           150: 
        !           151:       fprintf (asm_out_file, AS2 (p,%sst,%sst(1)), RP, RP);
        !           152:     }
        !           153:   else
        !           154:     {
        !           155:       while (*op && *op != '%')
        !           156:        fputc (*op++, asm_out_file);
        !           157:       fprintf (asm_out_file,AS2 ( ,%sst(1),%sst), RP, RP);
        !           158:     }
        !           159:   putc ('\n', asm_out_file);
        !           160: }
        !           161: 
        !           162: /* Moves X to memory location 8 below stack pointer
        !           163:    and returns an RTX for that memory location.
        !           164:    X should be a register, in DFmode or SFmode.  */
        !           165: 
        !           166: static rtx
        !           167: via_memory (x)
        !           168:      rtx x;
        !           169: {
        !           170:   if (!REG_P (x))
        !           171:     abort ();
        !           172:   if (GET_MODE (x) == DFmode)
        !           173:     {
        !           174:       rtx xops[1];
        !           175:       xops[0] = gen_rtx (REG, SImode, REGNO (x) + 1);
        !           176:       output_asm_insn ("push%L0 %0", xops);
        !           177:     }
        !           178:   output_asm_insn ("push%L0 %0", &x);
        !           179: }
        !           180: 
        !           181: /* Output an insn to copy the SFmode value in fp0 to OPERAND
        !           182:    without clobbering fp0.  */
        !           183: 
        !           184: void
        !           185: fp_store_sf (target)
        !           186:      rtx target;
        !           187: {
        !           188:   if (REG_P (target))
        !           189:     {
        !           190:       rtx xoperands[3];
        !           191:       xoperands[0] = stack_pointer_rtx;
        !           192:       xoperands[1] = AT_SP (Pmode);
        !           193:       xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4);
        !           194:       output_asm_insn (AS2 (add%L0,%2,%0), xoperands);
        !           195:       output_asm_insn ("fst%S0 %1", xoperands);
        !           196:       output_asm_insn ("pop%L0 %0", &target);
        !           197:     }
        !           198:   else if (GET_CODE (target) == MEM)
        !           199:     output_asm_insn ("fst%S0 %0", &target);
        !           200: }
        !           201: 
        !           202: /* Output an insn to pop an SF value from fp0 into TARGET.
        !           203:    This destroys the value of fp0.  */
        !           204: 
        !           205: void
        !           206: fp_pop_sf (target)
        !           207:      rtx target;
        !           208: {
        !           209:   if (REG_P (target))
        !           210:     {
        !           211:       rtx xoperands[3];
        !           212:       xoperands[0] = stack_pointer_rtx;
        !           213:       xoperands[1] = AT_SP (Pmode);
        !           214:       xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4);
        !           215:       output_asm_insn (AS2 (add%L0,%2,%0), xoperands);
        !           216:       output_asm_insn ("fstp%S0 %1", xoperands);
        !           217:       output_asm_insn ("pop%L0 %0", &target);
        !           218:       /* fp_pop_level--; */
        !           219:     }
        !           220:   else if (GET_CODE (target) == MEM)
        !           221:     {
        !           222:       /* fp_pop_level--; */
        !           223:       output_asm_insn ("fstp%S0 %0", &target);
        !           224:     }
        !           225:   else abort ();
        !           226: }
        !           227: 
        !           228: /* Copy the top of the fpu stack into TARGET, without popping.  */
        !           229: 
        !           230: void
        !           231: fp_store_df (target)
        !           232:      rtx target;
        !           233: {
        !           234:   if (REG_P (target))
        !           235:     {
        !           236:       rtx xoperands[4];
        !           237:       xoperands[0] = stack_pointer_rtx;
        !           238:       xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1);
        !           239:       xoperands[2] = AT_SP (Pmode);
        !           240:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8);
        !           241:       output_asm_insn (AS2 (add%L0,%3,%0), xoperands);
        !           242:       output_asm_insn ("fst%Q0 %2", xoperands);
        !           243:       output_asm_insn ("pop%L0 %0", &target);
        !           244:       output_asm_insn ("pop%L0 %1", xoperands);
        !           245:     }
        !           246:   else if (GET_CODE (target) == MEM)
        !           247:     output_asm_insn ("fst%Q0 %0", &target);
        !           248: }
        !           249: 
        !           250: /* Copy the top of the fpu stack into TARGET, with popping.  */
        !           251: 
        !           252: void
        !           253: fp_pop_df (target)
        !           254:      rtx target;
        !           255: {
        !           256:   if (REG_P (target))
        !           257:     {
        !           258:       rtx xoperands[4];
        !           259:       xoperands[0] = stack_pointer_rtx;
        !           260:       xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1);
        !           261:       xoperands[2] = AT_SP (Pmode);
        !           262:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8);
        !           263:       output_asm_insn (AS2 (add%L0,%3,%0), xoperands);
        !           264:       /* fp_pop_level--; */
        !           265:       output_asm_insn ("fstp%Q0 %2", xoperands);
        !           266:       output_asm_insn ("pop%L0 %0", &target);
        !           267:       output_asm_insn ("pop%L0 %1", xoperands);
        !           268:     }
        !           269:   else if (GET_CODE (target) == MEM)
        !           270:     {
        !           271:       /* fp_pop_level--; */
        !           272:       output_asm_insn ("fstp%z0 %0", &target);
        !           273:     }
        !           274: }
        !           275: 
        !           276: #if 0
        !           277: /* Pop the fp stack, convert value to integer and store in TARGET.
        !           278:    TARGET may be memory or register, and may have QI, HI or SImode.  */
        !           279: 
        !           280: void
        !           281: fp_pop_int (target)
        !           282:      rtx target;
        !           283: {
        !           284:   if (REG_P (target) || GET_MODE (target) != SImode)
        !           285:     {
        !           286:       rtx xxops[2];
        !           287:       xxops[0] = stack_pointer_rtx;
        !           288:       xxops[1] = gen_rtx (CONST_INT, VOIDmode, 4);
        !           289:       output_asm_insn (AS2 (sub%L0,%1,%0), xxops);
        !           290:       xxops[0] = AT_SP (Pmode);
        !           291:       /* fp_pop_level--; */
        !           292:       output_asm_insn ("fistps %0", xxops);
        !           293:       output_asm_insn ("pop%L0 %0", &target);
        !           294:     }
        !           295:   else if (GET_CODE (target) == MEM)
        !           296:     {
        !           297:       /* fp_pop_level--; */
        !           298:       output_asm_insn ("fistps %0", &target);
        !           299:     }
        !           300:   else abort ();
        !           301: }
        !           302: #endif
        !           303: 
        !           304: /* Push the SFmode value X onto the fpu stack.  */
        !           305: 
        !           306: void
        !           307: fp_push_sf (x)
        !           308:      rtx x;
        !           309: {
        !           310:   /* fp_pop_level++; */
        !           311:   if (REG_P (x))
        !           312:     {
        !           313:       rtx xoperands[2];
        !           314:       rtx xfops[3];
        !           315:       output_asm_insn ("push%L0 %0", &x);
        !           316:       xfops[0] = AT_SP (Pmode);
        !           317:       xfops[2] = gen_rtx (CONST_INT, VOIDmode, 4);
        !           318:       xfops[1] = stack_pointer_rtx;
        !           319:       output_asm_insn ("fld%S0 %0 \n\tadd%L0 %2,%1", xfops);
        !           320:     }
        !           321:   else
        !           322:     output_asm_insn ("fld%S0 %0", &x);
        !           323: }
        !           324: 
        !           325: /* Push the DFmode value X onto the fpu stack.  */
        !           326: 
        !           327: void
        !           328: fp_push_df (x)
        !           329:      rtx x;
        !           330: {
        !           331:   /* fp_pop_level++; */
        !           332: 
        !           333:   if (REG_P (x))
        !           334:     {
        !           335:       rtx xoperands[2];
        !           336:       rtx xfops[3];
        !           337:       xoperands[0] = x;
        !           338:       xoperands[1] = gen_rtx (REG, SImode, REGNO (x) + 1);
        !           339:       output_asm_insn ("push%L0 %1", xoperands);
        !           340:       output_asm_insn ("push%L0 %0", xoperands);
        !           341:       xfops[0] = AT_SP (Pmode);
        !           342:       xfops[2] = gen_rtx (CONST_INT, VOIDmode, 8);
        !           343:       xfops[1] = stack_pointer_rtx;
        !           344:       output_asm_insn ("fld%Q0 %0 \n\tadd%L0 %2,%1", xfops);
        !           345:     }
        !           346:   else if (GET_CODE (x) == MEM)
        !           347:     output_asm_insn ("fld%Q0 %0", &x);
        !           348: }
        !           349: 
        !           350: static char *output_move_const_single ();
        !           351: 
        !           352: static char *
        !           353: singlemove_string (operands)
        !           354:      rtx *operands;
        !           355: {
        !           356:   rtx x;
        !           357:   if (GET_CODE (operands[0]) == MEM
        !           358:       && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
        !           359:     {
        !           360:       if (XEXP (x, 0) != stack_pointer_rtx)
        !           361:        abort ();
        !           362:       return "push%L0 %1";
        !           363:     }
        !           364:   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
        !           365:     {
        !           366:       return output_move_const_single (operands);
        !           367:     }
        !           368:   else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
        !           369:     return AS2 (mov%L0,%1,%0);
        !           370:   else
        !           371:     {
        !           372:       output_asm_insn ("push%L0 %1", operands);
        !           373:       return "pop%L0 %0";
        !           374:     }
        !           375: }
        !           376: 
        !           377: /* Return a REG that occurs in ADDR with coefficient 1.
        !           378:    ADDR can be effectively incremented by incrementing REG.  */
        !           379: 
        !           380: static rtx
        !           381: find_addr_reg (addr)
        !           382:      rtx addr;
        !           383: {
        !           384:   while (GET_CODE (addr) == PLUS)
        !           385:     {
        !           386:       if (GET_CODE (XEXP (addr, 0)) == REG)
        !           387:        addr = XEXP (addr, 0);
        !           388:       else if (GET_CODE (XEXP (addr, 1)) == REG)
        !           389:        addr = XEXP (addr, 1);
        !           390:       else if (CONSTANT_P (XEXP (addr, 0)))
        !           391:        addr = XEXP (addr, 1);
        !           392:       else if (CONSTANT_P (XEXP (addr, 1)))
        !           393:        addr = XEXP (addr, 0);
        !           394:       else
        !           395:        abort ();
        !           396:     }
        !           397:   if (GET_CODE (addr) == REG)
        !           398:     return addr;
        !           399:   abort ();
        !           400: }
        !           401: 
        !           402: /* Output an insn to add the constant N to the register X.  */
        !           403: 
        !           404: static void
        !           405: asm_add (n, x)
        !           406:      int n;
        !           407:      rtx x;
        !           408: {
        !           409:   rtx xops[2];
        !           410:   xops[1] = x;
        !           411:   if (n < 0)
        !           412:     {
        !           413:       xops[0] = gen_rtx (CONST_INT, VOIDmode, -n);
        !           414:       output_asm_insn (AS2 (sub%L0,%0,%1), xops);
        !           415:     }
        !           416:   else if (n > 0)
        !           417:     {
        !           418:       xops[0] = gen_rtx (CONST_INT, VOIDmode, n);
        !           419:       output_asm_insn (AS2 (add%L0,%0,%1), xops);
        !           420:     }
        !           421: }
        !           422: 
        !           423: /* Output assembler code to perform a doubleword move insn
        !           424:    with operands OPERANDS.  */
        !           425: 
        !           426: char *
        !           427: output_move_double (operands)
        !           428:      rtx *operands;
        !           429: {
        !           430:   enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
        !           431:   rtx latehalf[2];
        !           432:   rtx addreg0 = 0, addreg1 = 0;
        !           433: 
        !           434:   /* First classify both operands.  */
        !           435: 
        !           436:   if (REG_P (operands[0]))
        !           437:     optype0 = REGOP;
        !           438:   else if (offsettable_memref_p (operands[0]))
        !           439:     optype0 = OFFSOP;
        !           440:   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
        !           441:     optype0 = POPOP;
        !           442:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
        !           443:     optype0 = PUSHOP;
        !           444:   else if (GET_CODE (operands[0]) == MEM)
        !           445:     optype0 = MEMOP;
        !           446:   else
        !           447:     optype0 = RNDOP;
        !           448: 
        !           449:   if (REG_P (operands[1]))
        !           450:     optype1 = REGOP;
        !           451:   else if (CONSTANT_P (operands[1])
        !           452:           || GET_CODE (operands[1]) == CONST_DOUBLE)
        !           453:     optype1 = CNSTOP;
        !           454:   else if (offsettable_memref_p (operands[1]))
        !           455:     optype1 = OFFSOP;
        !           456:   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
        !           457:     optype1 = POPOP;
        !           458:   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
        !           459:     optype1 = PUSHOP;
        !           460:   else if (GET_CODE (operands[1]) == MEM)
        !           461:     optype1 = MEMOP;
        !           462:   else
        !           463:     optype1 = RNDOP;
        !           464: 
        !           465:   /* Check for the cases that the operand constraints are not
        !           466:      supposed to allow to happen.  Abort if we get one,
        !           467:      because generating code for these cases is painful.  */
        !           468: 
        !           469:   if (optype0 == RNDOP || optype1 == RNDOP)
        !           470:     abort ();
        !           471: 
        !           472:   /* If one operand is decrementing and one is incrementing
        !           473:      decrement the former register explicitly
        !           474:      and change that operand into ordinary indexing.  */
        !           475: 
        !           476:   if (optype0 == PUSHOP && optype1 == POPOP)
        !           477:     {
        !           478:       operands[0] = XEXP (XEXP (operands[0], 0), 0);
        !           479:       asm_add (-8, operands[0]);
        !           480:       operands[0] = gen_rtx (MEM, DImode, operands[0]);
        !           481:       optype0 = OFFSOP;
        !           482:     }
        !           483:   if (optype0 == POPOP && optype1 == PUSHOP)
        !           484:     {
        !           485:       operands[1] = XEXP (XEXP (operands[1], 0), 0);
        !           486:       asm_add (-8, operands[1]);
        !           487:       operands[1] = gen_rtx (MEM, DImode, operands[1]);
        !           488:       optype1 = OFFSOP;
        !           489:     }
        !           490: 
        !           491:   /* If an operand is an unoffsettable memory ref, find a register
        !           492:      we can increment temporarily to make it refer to the second word.  */
        !           493: 
        !           494:   if (optype0 == MEMOP)
        !           495:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
        !           496: 
        !           497:   if (optype1 == MEMOP)
        !           498:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
        !           499: 
        !           500:   /* Ok, we can do one word at a time.
        !           501:      Normally we do the low-numbered word first,
        !           502:      but if either operand is autodecrementing then we
        !           503:      do the high-numbered word first.
        !           504: 
        !           505:      In either case, set up in LATEHALF the operands to use
        !           506:      for the high-numbered word and in some cases alter the
        !           507:      operands in OPERANDS to be suitable for the low-numbered word.  */
        !           508: 
        !           509:   if (optype0 == REGOP)
        !           510:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
        !           511:   else if (optype0 == OFFSOP)
        !           512:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
        !           513:   else
        !           514:     latehalf[0] = operands[0];
        !           515: 
        !           516:   if (optype1 == REGOP)
        !           517:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
        !           518:   else if (optype1 == OFFSOP)
        !           519:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
        !           520:   else if (optype1 == CNSTOP)
        !           521:     {
        !           522:       if (CONSTANT_P (operands[1]))
        !           523:        latehalf[1] = const0_rtx;
        !           524:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
        !           525:        {
        !           526:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
        !           527:                                 CONST_DOUBLE_HIGH (operands[1]));
        !           528:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
        !           529:                                 CONST_DOUBLE_LOW (operands[1]));
        !           530:        }
        !           531:     }
        !           532:   else
        !           533:     latehalf[1] = operands[1];
        !           534: 
        !           535:   /* If insn is effectively movd N (sp),-(sp) then we will do the
        !           536:      high word first.  We should use the adjusted operand 1 (which is N+4 (sp))
        !           537:      for the low word as well, to compensate for the first decrement of sp.  */
        !           538:   if (optype0 == PUSHOP
        !           539:       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
        !           540:       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
        !           541:     operands[1] = latehalf[1];
        !           542: 
        !           543:   /* If one or both operands autodecrementing,
        !           544:      do the two words, high-numbered first.  */
        !           545: 
        !           546:   /* Likewise,  the first move would clobber the source of the second one,
        !           547:      do them in the other order.  This happens only for registers;
        !           548:      such overlap can't happen in memory unless the user explicitly
        !           549:      sets it up, and that is an undefined circumstance.  */
        !           550: 
        !           551:   if (optype0 == PUSHOP || optype1 == PUSHOP
        !           552:       || (optype0 == REGOP && optype1 == REGOP
        !           553:          && REGNO (operands[0]) == REGNO (latehalf[1])))
        !           554:     {
        !           555:       /* Make any unoffsettable addresses point at high-numbered word.  */
        !           556:       if (addreg0)
        !           557:        asm_add (4, addreg0);
        !           558:       if (addreg1)
        !           559:        asm_add (4, addreg1);
        !           560: 
        !           561:       /* Do that word.  */
        !           562:       output_asm_insn (singlemove_string (latehalf), latehalf);
        !           563: 
        !           564:       /* Undo the adds we just did.  */
        !           565:       if (addreg0)
        !           566:          asm_add (-4, addreg0);
        !           567:       if (addreg1)
        !           568:        asm_add (-4, addreg1);
        !           569: 
        !           570:       /* Do low-numbered word.  */
        !           571:       return singlemove_string (operands);
        !           572:     }
        !           573: 
        !           574:   /* Normal case: do the two words, low-numbered first.  */
        !           575: 
        !           576:   output_asm_insn (singlemove_string (operands), operands);
        !           577: 
        !           578:   /* Make any unoffsettable addresses point at high-numbered word.  */
        !           579:   if (addreg0)
        !           580:     asm_add (4, addreg0);
        !           581:   if (addreg1)
        !           582:     asm_add (4, addreg1);
        !           583: 
        !           584:   /* Do that word.  */
        !           585:   output_asm_insn (singlemove_string (latehalf), latehalf);
        !           586: 
        !           587:   /* Undo the adds we just did.  */
        !           588:   if (addreg0)
        !           589:     asm_add (-4, addreg0);
        !           590:   if (addreg1)
        !           591:     asm_add (-4, addreg1);
        !           592: 
        !           593:   return "";
        !           594: }
        !           595: 
        !           596: int
        !           597: standard_80387_constant_p (x)
        !           598:      rtx x;
        !           599: {
        !           600:   union { double d; int i[2];} u;
        !           601:   register double d;
        !           602:   u.i[0] = XINT (x, 0);
        !           603:   u.i[1] = XINT (x, 1);
        !           604:   d = u.d;
        !           605: 
        !           606:   if (d == 0)
        !           607:     return 1;
        !           608:   if (d == 1)
        !           609:     return 2;
        !           610:   /* Note that on the 80387, other constants, such as pi,
        !           611:      are much slower to load as standard constants
        !           612:      than to load from doubles in memory!  */
        !           613: 
        !           614:   return 0;
        !           615: }
        !           616: 
        !           617: static char *
        !           618: output_move_const_double (operands)
        !           619:      rtx *operands;
        !           620: {
        !           621:   if (FP_REG_P (operands[0]))
        !           622:     {
        !           623:       int conval = standard_80387_constant_p (operands[1]);
        !           624: 
        !           625:       /* fp_pop_level++; */
        !           626:       if (conval == 1)
        !           627:        return "fldz";
        !           628:       if (conval == 2)
        !           629:        return "fld1";
        !           630:       /* fp_pop_level--; */
        !           631:     }
        !           632: 
        !           633:   output_move_double (operands);
        !           634: }
        !           635: 
        !           636: 
        !           637: static char *
        !           638: output_move_const_single (operands)
        !           639:      rtx *operands;
        !           640: {
        !           641:   if (FP_REG_P (operands[0]))
        !           642:     {
        !           643:       int conval = standard_80387_constant_p (operands[1]);
        !           644: 
        !           645:       /* fp_pop_level++; */
        !           646:       if (conval == 1)
        !           647:        return "fldz";
        !           648:       if (conval == 2)
        !           649:        return "fld1";
        !           650:       /* fp_pop_level--; */
        !           651:     }
        !           652:   if (GET_CODE (operands[1]) == CONST_DOUBLE)
        !           653:     {
        !           654:       union { int i[2]; double d;} u1;
        !           655:       union { int i; float f;} u2;
        !           656:       u1.i[0] = CONST_DOUBLE_LOW (operands[1]);
        !           657:       u1.i[1] = CONST_DOUBLE_HIGH (operands[1]);
        !           658:       u2.f = u1.d;
        !           659:       operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i);
        !           660:     }
        !           661:   return singlemove_string (operands);
        !           662: }
        !           663: 
        !           664: /* Output an insn to move an SF value from FROM to TO.
        !           665:    The kinds of operands are not restricted
        !           666:    except that they may not both be in memory.  */
        !           667: 
        !           668: void
        !           669: output_movsf (to, from)
        !           670:      rtx from, to;
        !           671: {
        !           672:   rtx xops[2];
        !           673:   xops[0] = to;
        !           674:   xops[1] = from;
        !           675:   if (FP_REG_P (from) || FP_REG_P (to))
        !           676:     {
        !           677:       from = xops[1];
        !           678:     }
        !           679: 
        !           680:   if (FP_REG_P (from))
        !           681:     {
        !           682: #if 0
        !           683:        {
        !           684:          if (REGNO (from) != REGNO (to))
        !           685:            {
        !           686:              output_asm_insn ("fld%S0 %1 \n\tfstp%S0 %0", xops);
        !           687:            }
        !           688:        }
        !           689:       else
        !           690: #endif
        !           691: 
        !           692:       if (! FP_REG_P (to))
        !           693:        fp_pop_sf (to);
        !           694:     }
        !           695:   else if (FP_REG_P (to))
        !           696:     fp_push_sf (from);
        !           697:   else
        !           698:     output_asm_insn (singlemove_string (xops), xops);
        !           699: }
        !           700: 
        !           701: /* Output an insn to move a DF value from FROM to TO.
        !           702:    The kinds of operands are not restricted
        !           703:    except that they may not both be in memory.  */
        !           704: 
        !           705: void
        !           706: output_movdf (to, from)
        !           707:      rtx from, to;
        !           708: {
        !           709:   rtx xops[2];
        !           710:   xops[0] = to;
        !           711:   xops[1] = from;
        !           712:   if (FP_REG_P (from) || FP_REG_P (to))
        !           713:     {
        !           714:       from = xops[1];
        !           715:       to = xops[0];
        !           716:     }
        !           717:   if (FP_REG_P (from))
        !           718:     {
        !           719: #if 0
        !           720:        {
        !           721:          if (REGNO (from) != REGNO (to))
        !           722:            abort ();
        !           723: /*         output_asm_insn ("fld%Q0 %1 \n\t fstp%Q0 %0", xops);*/
        !           724:        }
        !           725:       else
        !           726:        {
        !           727: #endif
        !           728:       if (! FP_REG_P (to))
        !           729:        fp_pop_df (to);
        !           730:     }
        !           731:   else if (FP_REG_P (to))
        !           732:     fp_push_df (from);
        !           733:   else
        !           734:     output_asm_insn (output_move_double (xops), xops);
        !           735: }
        !           736: 
        !           737: /* does move of FROM to TO where the mode is the minimum of the
        !           738: two */
        !           739: 
        !           740: static void
        !           741: output_movf (to, from)
        !           742:      rtx to, from;
        !           743: {
        !           744:   if (GET_MODE (from) == SFmode || GET_MODE (to) == SFmode)
        !           745:     output_movsf (to, from);
        !           746:   else
        !           747:     output_movdf (to, from);
        !           748: }
        !           749: 
        !           750: /* Return the best assembler insn template
        !           751:    for moving operands[1] into operands[0] as a fullword.  */
        !           752: 
        !           753: void
        !           754: function_prologue (file, size)
        !           755:      FILE *file;
        !           756:      int size;
        !           757: {
        !           758:   register int regno;
        !           759:   int nregs, limit;
        !           760:   rtx xops[4];
        !           761:   extern int frame_pointer_needed;
        !           762: 
        !           763:   /* fp_pop_level = 0; */
        !           764:   xops[0] = stack_pointer_rtx;
        !           765:   xops[1] = frame_pointer_rtx;
        !           766:   xops[2] = gen_rtx (CONST_INT, VOIDmode, size);
        !           767:   if (frame_pointer_needed)
        !           768:     {
        !           769:       output_asm_insn ("push%L0 %1", xops);
        !           770:       output_asm_insn (AS2 (mov%L0,%0,%1), xops);
        !           771:       if (size)
        !           772:        output_asm_insn (AS2 (sub%L0,%2,%0), xops);
        !           773:     }
        !           774: 
        !           775:   /* Note If use enter it is NOT reversed args.
        !           776:      This one is not reversed from intel!!
        !           777:      I think enter is slower.  Also sdb doesn't like it.
        !           778:      But if you want it the code is:
        !           779:      {
        !           780:      xops[3] = const0_rtx;
        !           781:      output_asm_insn ("enter %2,%3", xops);
        !           782:      }
        !           783:      */
        !           784:   nregs = 0;
        !           785:   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
        !           786:   for (regno = limit - 1; regno >= 0; regno--)
        !           787:     if (regs_ever_live[regno] && ! call_used_regs[regno])
        !           788:       {
        !           789:        fprintf (file, "\tpush%s %se%s\n", L_SIZE, RP, hi_reg_name[regno]);
        !           790:       }
        !           791: }
        !           792: 
        !           793: void
        !           794: function_epilogue (file, size)
        !           795:      FILE *file;
        !           796:      int size;
        !           797: {
        !           798:   register int regno;
        !           799:   register int nregs, limit;
        !           800:   int assure_sp_pos;
        !           801:   extern int frame_pointer_needed;
        !           802:   extern int current_function_pops_args;
        !           803:   extern int current_function_args_size;
        !           804:   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
        !           805:   nregs = 0;
        !           806: 
        !           807: 
        !           808:   for (regno = (limit -1); regno >= 0; regno--)
        !           809:     if (regs_ever_live[regno] && ! call_used_regs[regno])
        !           810:       nregs++;
        !           811: 
        !           812:   /* sp is often  unreliable so we must go off the frame pointer,
        !           813:    */
        !           814: 
        !           815:   if (nregs && frame_pointer_needed)
        !           816:     {
        !           817:       rtx xops[2];
        !           818:       xops[0] = adj_offsettable_operand (AT_BP (Pmode),
        !           819:                                         -size -(nregs*(UNITS_PER_WORD)));
        !           820:       xops[1] = stack_pointer_rtx;
        !           821:       output_asm_insn (AS2 (lea%L0,%0,%1), xops);
        !           822:     }
        !           823:   for (regno = 0; regno < limit; regno++)
        !           824:     {
        !           825:       if (regs_ever_live[regno] && ! call_used_regs[regno])
        !           826:        {
        !           827:          fprintf (file, "\tpop%s ", L_SIZE);
        !           828:          fprintf (file, "%se%s\n", RP, hi_reg_name[regno]);
        !           829:        }
        !           830:     }
        !           831: 
        !           832:   if (frame_pointer_needed)
        !           833:     fprintf (file, "\tleave\n");
        !           834:   if (current_function_pops_args && current_function_args_size)
        !           835:     fprintf (file, "\tret %s%d\n", IP,
        !           836:             (current_function_args_size
        !           837:              + (current_function_returns_struct ? 4 : 0)));
        !           838:   else if (current_function_returns_struct)
        !           839:     fprintf (file, "\tret %s4\n", IP);
        !           840:   else
        !           841:     fprintf (file, "\tret\n");
        !           842: }
        !           843: 
        !           844: int
        !           845: hard_regno_mode_ok (regno, mode)
        !           846:      int regno;
        !           847:      enum machine_mode mode;
        !           848: {
        !           849:   return
        !           850:     (regno < 2 ? 1
        !           851:      /* Used to reject floating modes here */
        !           852:      : regno < 4 ? 1
        !           853:      : regno >= 8 ? mode == DFmode || mode == SFmode
        !           854:      : mode != QImode);
        !           855: }
        !           856: 
        !           857: /* Print the name of a register based on its machine mode and number.
        !           858:    If CODE is 'w', pretend the mode is HImode.  */
        !           859: 
        !           860: #define PRINT_REG(X, CODE, FILE) \
        !           861:   do { fprintf (FILE, "%s", RP);                       \
        !           862:        switch ((CODE == 'w' ? 2 : GET_MODE_SIZE (GET_MODE (X)))) \
        !           863:         {                                              \
        !           864:         case 4:                                        \
        !           865:         case 8:                                        \
        !           866:           if (!FP_REG_P (X)) fputs ("e", FILE);        \
        !           867:         case 2:                                        \
        !           868:           fputs (hi_reg_name[REGNO (X)], FILE);        \
        !           869:           break;                                       \
        !           870:         case 1:                                        \
        !           871:           fputs (qi_reg_name[REGNO (X)], FILE);        \
        !           872:         }                                              \
        !           873:      } while (0)
        !           874: 
        !           875: /* Meaning of CODE:
        !           876:    f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
        !           877:    L,W,B,Q,S -- print the opcode suffix for specified size of operand.
        !           878:    R -- print the prefix for register names.
        !           879:    z -- print the opcode suffix for the size of the current operand.
        !           880:    * -- print a star (in certain assembler syntax)
        !           881:    w -- print the operand as if it's a "word" (HImode) even if it isn't.
        !           882:    c -- don't print special prefixes before constant operands.
        !           883: */
        !           884: 
        !           885: void
        !           886: print_operand (file, x, code)
        !           887:      FILE *file;
        !           888:      rtx x;
        !           889:      int code;
        !           890: {
        !           891:   if (code)
        !           892:     {
        !           893:       switch (code)
        !           894:        {
        !           895:        case '*':
        !           896:          if (USE_STAR)
        !           897:            putc ('*', file);
        !           898:          return;
        !           899: 
        !           900:        case 'L':
        !           901:          PUT_OP_SIZE (code, 'l', file);
        !           902:          return;
        !           903: 
        !           904:        case 'W':
        !           905:          PUT_OP_SIZE (code, 'w', file);
        !           906:          return;
        !           907: 
        !           908:        case 'B':
        !           909:          PUT_OP_SIZE (code, 'b', file);
        !           910:          return;
        !           911: 
        !           912:        case 'Q':
        !           913:          PUT_OP_SIZE (code, 'l', file);
        !           914:          return;
        !           915: 
        !           916:        case 'S':
        !           917:          PUT_OP_SIZE (code, 's', file);
        !           918:          return;
        !           919: 
        !           920:        case 'R':
        !           921:          fprintf (file, "%s", RP);
        !           922:          return;
        !           923: 
        !           924:        case 'z':
        !           925:          /* this is the size of op from size of operand */
        !           926:          switch (GET_MODE_SIZE (GET_MODE (x)))
        !           927:            {
        !           928:            case 2:
        !           929:              PUT_OP_SIZE ('W', 'w', file);
        !           930:              return;
        !           931:            case 4:
        !           932:              if (GET_MODE (x) == SFmode)
        !           933:                {
        !           934:                  PUT_OP_SIZE ('S', 's', file);
        !           935:                  return;
        !           936:                }
        !           937:              else
        !           938:                PUT_OP_SIZE ('L', 'l', file);
        !           939:              return;
        !           940:            case 8:
        !           941:              if (!FP_REG_P (x)) PUT_OP_SIZE ('Q', 'l', file);
        !           942:              return;
        !           943:            case 1:
        !           944:              PUT_OP_SIZE ('B', 'b', file);
        !           945:              return;
        !           946:            }
        !           947:        }
        !           948:     }
        !           949:   if (GET_CODE (x) == REG)
        !           950:     {
        !           951:       PRINT_REG (x, code, file);
        !           952:     }
        !           953:   else if (GET_CODE (x) == MEM)
        !           954:     {
        !           955:       PRINT_PTR (x, file);
        !           956:       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
        !           957:        output_addr_const (file, XEXP (x, 0));
        !           958:       else
        !           959:        output_address (XEXP (x, 0));
        !           960:     }
        !           961:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
        !           962:     {
        !           963:       union { double d; int i[2]; } u;
        !           964:       union { float f; int i; } u1;
        !           965:       u.i[0] = CONST_DOUBLE_LOW (x);
        !           966:       u.i[1] = CONST_DOUBLE_HIGH (x);
        !           967:       u1.f = u.d;
        !           968:       if (code == 'f')
        !           969:         fprintf (file, "%.22e", u1.f);
        !           970:       else
        !           971:         {
        !           972:          PRINT_IMMED_PREFIX (file);
        !           973:          fprintf (file, "0x%x", u1.i);
        !           974:        }
        !           975:     }
        !           976:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
        !           977:     {
        !           978:       union { double d; int i[2]; } u;
        !           979:       u.i[0] = CONST_DOUBLE_LOW (x);
        !           980:       u.i[1] = CONST_DOUBLE_HIGH (x);
        !           981:       fprintf (file, "%.22e", u.d);
        !           982:     }
        !           983:   else 
        !           984:     {
        !           985:       if (code != 'c')
        !           986:        {
        !           987:          if (GET_CODE (x) == CONST_INT)
        !           988:            PRINT_IMMED_PREFIX (file);
        !           989:          else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
        !           990:            PRINT_OFFSET_PREFIX (file);
        !           991:        }
        !           992:       output_addr_const (file, x);
        !           993:     }
        !           994: }
        !           995: 
        !           996: /* Print a memory operand whose address is ADDR.  */
        !           997: 
        !           998: void
        !           999: print_operand_address (file, addr)
        !          1000:      FILE *file;
        !          1001:      register rtx addr;
        !          1002: {
        !          1003:   register rtx reg1, reg2, breg, ireg;
        !          1004:   rtx offset;
        !          1005: 
        !          1006:   switch (GET_CODE (addr))
        !          1007:     {
        !          1008:     case REG:
        !          1009:       ADDR_BEG (file);
        !          1010:       fprintf (file, "%se", RP);
        !          1011:       fputs (hi_reg_name[REGNO (addr)], file);
        !          1012:       ADDR_END (file);
        !          1013:       break;
        !          1014: 
        !          1015:     case PLUS:
        !          1016:       reg1 = 0;
        !          1017:       reg2 = 0;
        !          1018:       ireg = 0;
        !          1019:       breg = 0;
        !          1020:       offset = 0;
        !          1021:       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
        !          1022:        {
        !          1023:          offset = XEXP (addr, 0);
        !          1024:          addr = XEXP (addr, 1);
        !          1025:        }
        !          1026:       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
        !          1027:        {
        !          1028:          offset = XEXP (addr, 1);
        !          1029:          addr = XEXP (addr, 0);
        !          1030:        }
        !          1031:       if (GET_CODE (addr) != PLUS) ;
        !          1032:       else if (GET_CODE (XEXP (addr, 0)) == MULT)
        !          1033:        {
        !          1034:          reg1 = XEXP (addr, 0);
        !          1035:          addr = XEXP (addr, 1);
        !          1036:        }
        !          1037:       else if (GET_CODE (XEXP (addr, 1)) == MULT)
        !          1038:        {
        !          1039:          reg1 = XEXP (addr, 1);
        !          1040:          addr = XEXP (addr, 0);
        !          1041:        }
        !          1042:       else if (GET_CODE (XEXP (addr, 0)) == REG)
        !          1043:        {
        !          1044:          reg1 = XEXP (addr, 0);
        !          1045:          addr = XEXP (addr, 1);
        !          1046:        }
        !          1047:       else if (GET_CODE (XEXP (addr, 1)) == REG)
        !          1048:        {
        !          1049:          reg1 = XEXP (addr, 1);
        !          1050:          addr = XEXP (addr, 0);
        !          1051:        }
        !          1052:       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
        !          1053:        {
        !          1054:          if (reg1 == 0) reg1 = addr;
        !          1055:          else reg2 = addr;
        !          1056:          addr = 0;
        !          1057:        }
        !          1058:       if (offset != 0)
        !          1059:        {
        !          1060:          if (addr != 0) abort ();
        !          1061:          addr = offset;
        !          1062:        }
        !          1063:       if ((reg1 && GET_CODE (reg1) == MULT)
        !          1064:          || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
        !          1065:        {
        !          1066:          breg = reg2;
        !          1067:          ireg = reg1;
        !          1068:        }
        !          1069:       else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
        !          1070:        {
        !          1071:          breg = reg1;
        !          1072:          ireg = reg2;
        !          1073:        }
        !          1074: 
        !          1075:       if (ireg != 0 || breg != 0)
        !          1076:        {
        !          1077:          int scale = 1;
        !          1078: 
        !          1079:          if (addr != 0)
        !          1080:            {
        !          1081:              if (GET_CODE (addr) == LABEL_REF)
        !          1082:                output_asm_label (addr);
        !          1083:              else
        !          1084:                output_addr_const (file, addr);
        !          1085:            }
        !          1086: 
        !          1087:          if (ireg != 0 && GET_CODE (ireg) == MULT)
        !          1088:            {
        !          1089:              scale = INTVAL (XEXP (ireg, 1));
        !          1090:              ireg = XEXP (ireg, 0);
        !          1091:            }
        !          1092:          /* output breg+ireg*scale */
        !          1093:          PRINT_B_I_S (breg, ireg, scale, file);
        !          1094:          break;
        !          1095:        }
        !          1096: 
        !          1097:     default:
        !          1098:       if (GET_CODE (addr) == CONST_INT
        !          1099:          && INTVAL (addr) < 0x8000
        !          1100:          && INTVAL (addr) >= -0x8000)
        !          1101:        fprintf (file, "%d", INTVAL (addr));
        !          1102:       else
        !          1103:        output_addr_const (file, addr);
        !          1104:     }
        !          1105: }
        !          1106: 
        !          1107: /* Set the cc_status for the results of an insn whose pattern is EXP.
        !          1108:    On the 80386, we assume that only test and compare insns, as well
        !          1109:    as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT,
        !          1110:    ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
        !          1111:    Also, we assume that jumps and moves don't affect the condition codes.
        !          1112:    All else, clobbers the condition codes, by assumption.
        !          1113: 
        !          1114:    We assume that ALL add, minus, etc. instructions effect the condition
        !          1115:    codes.  This MUST be consistent with i386.md.  */
        !          1116: 
        !          1117: notice_update_cc (exp)
        !          1118:      rtx exp;
        !          1119: {
        !          1120:   if (GET_CODE (exp) == SET)
        !          1121:     {
        !          1122:       /* Jumps do not alter the cc's.  */
        !          1123:       if (SET_DEST (exp) == pc_rtx)
        !          1124:        return;
        !          1125:       /* Moving register or memory into a register:
        !          1126:         it doesn't alter the cc's, but it might invalidate
        !          1127:         the RTX's which we remember the cc's came from.
        !          1128:         (Note that moving a constant 0 or 1 MAY set the cc's).  */
        !          1129:       if (REG_P (SET_DEST (exp))
        !          1130:          && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM))
        !          1131:        {
        !          1132:          if (cc_status.value1
        !          1133:              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
        !          1134:            cc_status.value1 = 0;
        !          1135:          if (cc_status.value2
        !          1136:              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
        !          1137:            cc_status.value2 = 0;
        !          1138:          return;
        !          1139:        }
        !          1140:       /* Moving register into memory doesn't alter the cc's.
        !          1141:         It may invalidate the RTX's which we remember the cc's came from.  */
        !          1142:       if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp)))
        !          1143:        {
        !          1144:          if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
        !          1145:            cc_status.value1 = 0;
        !          1146:          if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
        !          1147:            cc_status.value2 = 0;
        !          1148:          return;
        !          1149:        }
        !          1150:       /* Function calls clobber the cc's.  */
        !          1151:       else if (GET_CODE (SET_SRC (exp)) == CALL)
        !          1152:        {
        !          1153:          CC_STATUS_INIT;
        !          1154:          return;
        !          1155:        }
        !          1156:       /* Tests and compares set the cc's in predictable ways.  */
        !          1157:       else if (SET_DEST (exp) == cc0_rtx)
        !          1158:        {
        !          1159:          CC_STATUS_INIT;
        !          1160:          cc_status.value1 = SET_SRC (exp);
        !          1161:          return;
        !          1162:        }
        !          1163:       /* Certain instructions effect the condition codes. */
        !          1164:       else if (GET_MODE (SET_SRC (exp)) == SImode
        !          1165:               || GET_MODE (SET_SRC (exp)) == HImode
        !          1166:               || GET_MODE (SET_SRC (exp)) == QImode)
        !          1167:        switch (GET_CODE (SET_SRC (exp)))
        !          1168:          {
        !          1169:          case ASHIFTRT: case LSHIFTRT:
        !          1170:          case ASHIFT: case LSHIFT:
        !          1171:            /* Shifts on the 386 don't set the condition codes if the
        !          1172:               shift count is zero. */
        !          1173:            if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
        !          1174:              {
        !          1175:                CC_STATUS_INIT;
        !          1176:                break;
        !          1177:              }
        !          1178:            /* We assume that the CONST_INT is non-zero (this rtx would
        !          1179:               have been deleted if it were zero. */
        !          1180: 
        !          1181:          case PLUS: case MINUS: case NEG:
        !          1182:          case AND: case IOR: case XOR:
        !          1183:            cc_status.flags = CC_NO_OVERFLOW;
        !          1184:            cc_status.value1 = SET_SRC (exp);
        !          1185:            cc_status.value2 = SET_DEST (exp);
        !          1186:            break;
        !          1187: 
        !          1188:          default:
        !          1189:            CC_STATUS_INIT;
        !          1190:          }
        !          1191:       else
        !          1192:        {
        !          1193:          CC_STATUS_INIT;
        !          1194:        }
        !          1195:     }
        !          1196:   else if (GET_CODE (exp) == PARALLEL
        !          1197:           && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
        !          1198:     {
        !          1199:       if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
        !          1200:        return;
        !          1201:       if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
        !          1202:        {
        !          1203:          CC_STATUS_INIT;
        !          1204:          cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
        !          1205:          return;
        !          1206:        }
        !          1207:       CC_STATUS_INIT;
        !          1208:     }
        !          1209:   else
        !          1210:     {
        !          1211:       CC_STATUS_INIT;
        !          1212:     }
        !          1213: }
        !          1214: 
        !          1215: /* Nonzero if the top of the fpu stack dies in this insn.  */
        !          1216: 
        !          1217: int
        !          1218: top_dead_p (insn)
        !          1219:      rtx insn;
        !          1220: {
        !          1221:   extern int optimize;
        !          1222:   if (optimize)
        !          1223:     return (find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG)
        !          1224:            || find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG + 1));
        !          1225: 
        !          1226:   if (GET_CODE (insn) == CALL_INSN)
        !          1227:     return call_top_dead_p (insn);
        !          1228: 
        !          1229:   return fp_top_dead_p1 (insn);
        !          1230: }
        !          1231: 
        !          1232: /* Following is used after a call_value insn
        !          1233:    if obey_regdecls there will not be the REG_DEAD notes
        !          1234:    to go by (there won't be any cross jumping to worry about
        !          1235:    either), and we depend on seeing if the FP_TOP is used
        !          1236:    in the next two insn's.  Otherwise we depend on the
        !          1237:    REG_DEAD notes.
        !          1238:    */
        !          1239: 
        !          1240: static int
        !          1241: call_top_dead_p (insn)
        !          1242:      rtx insn;
        !          1243: {
        !          1244:   int i;
        !          1245:   for (i = 0; i < 3; i++)
        !          1246:     {
        !          1247:       insn = NEXT_INSN (insn);
        !          1248:       if (insn == 0)
        !          1249:        return 1;
        !          1250:       if (GET_CODE (insn) == NOTE || GET_CODE (insn) == CODE_LABEL)
        !          1251:        continue;
        !          1252:       if (GET_CODE (insn) == BARRIER)
        !          1253:        abort ();
        !          1254:       if (GET_CODE (PATTERN (insn)) == SET
        !          1255:          && SET_DEST (PATTERN (insn)) != stack_pointer_rtx)
        !          1256:        return (!(mentions_fp_top (SET_SRC (PATTERN (insn)))));
        !          1257:       if (GET_CODE (PATTERN (insn)) == CALL)
        !          1258:        return 1;
        !          1259:       if (GET_CODE (PATTERN (insn)) == USE)
        !          1260:        return (! FP_REG_P (XEXP (PATTERN (insn), 0)));
        !          1261:     }
        !          1262:   return 1;
        !          1263: }
        !          1264: 
        !          1265: /* Return 1 if current val of fpu top-of-stack appears unused
        !          1266:    in rest of this basic block.  */
        !          1267: 
        !          1268: static int
        !          1269: fp_top_dead_p1 (insn)
        !          1270:      rtx insn;
        !          1271: {
        !          1272:   for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
        !          1273:     {
        !          1274:       switch (GET_CODE (insn))
        !          1275:        {
        !          1276:        case CALL_INSN:
        !          1277:          /* Function calls clobber this value, so it's dead.  */
        !          1278:        case JUMP_INSN:
        !          1279:        case CODE_LABEL:
        !          1280:          return 1;
        !          1281: 
        !          1282:        case INSN:
        !          1283:          if (GET_CODE (PATTERN (insn)) == SET)
        !          1284:            {
        !          1285:              if ((mentions_fp_top (SET_SRC (PATTERN (insn)))))
        !          1286:                return 0;
        !          1287:              else if (FP_REG_P (SET_DEST (PATTERN (insn))))
        !          1288:                return 1;
        !          1289:            }
        !          1290:          else if (mentions_fp_top (PATTERN (insn)))
        !          1291:            return 0;
        !          1292:          break;
        !          1293:        }
        !          1294:     }
        !          1295:   return 1;
        !          1296: }
        !          1297: 
        !          1298: /* Return 1 if X involves an FPU register.  */
        !          1299: 
        !          1300: static int
        !          1301: mentions_fp_top (x)
        !          1302:      rtx x;
        !          1303: {
        !          1304:   register RTX_CODE code;
        !          1305: 
        !          1306:   code = GET_CODE (x);
        !          1307:   switch (code)
        !          1308:     {
        !          1309:     case LABEL_REF:
        !          1310:     case SYMBOL_REF:
        !          1311:     case CONST_INT:
        !          1312:     case CONST:
        !          1313:     case CC0:
        !          1314:     case PC:
        !          1315:     case CLOBBER:
        !          1316:     case MEM:
        !          1317:       return 0;
        !          1318: 
        !          1319:     case REG:
        !          1320:       return FP_REGNO_P (REGNO (x));
        !          1321:     }
        !          1322: 
        !          1323:   /* Recursively scan the operands of this expression.  */
        !          1324:   {
        !          1325:     register char *fmt = GET_RTX_FORMAT (code);
        !          1326:     register int i;
        !          1327: 
        !          1328:     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        !          1329:       {
        !          1330:        if (fmt[i] == 'e')
        !          1331:          {
        !          1332:            if (mentions_fp_top (XEXP (x, i)))
        !          1333:              return 1;
        !          1334:          }
        !          1335:        if (fmt[i] == 'E')
        !          1336:          {
        !          1337:            register int j;
        !          1338:            for (j = 0; j < XVECLEN (x, i); j++)
        !          1339:              if (mentions_fp_top (XVECEXP (x, i, j)))
        !          1340:                return 1;
        !          1341:          }
        !          1342:       }
        !          1343:   }
        !          1344:   return 0;
        !          1345: }
        !          1346: 
        !          1347: /* Some asm-dependent functions. */
        !          1348: 
        !          1349: #ifdef MASM
        !          1350: #include "masm386.c"
        !          1351: #endif

unix.superglobalmegacorp.com

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