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

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

unix.superglobalmegacorp.com

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