Annotation of gcc/output-sparc.c, revision 1.1.1.7

1.1       root        1: /* Subroutines for insn-output.c for Sun SPARC.
1.1.1.4   root        2:    Copyright (C) 1987, 1988 Free Software Foundation, Inc.
1.1       root        3:    Contributed by Michael Tiemann ([email protected])
                      4: 
                      5: This file is part of GNU CC.
                      6: 
                      7: GNU CC is distributed in the hope that it will be useful,
                      8: but WITHOUT ANY WARRANTY.  No author or distributor
                      9: accepts responsibility to anyone for the consequences of using it
                     10: or for whether it serves any particular purpose or works at all,
                     11: unless he says so in writing.  Refer to the GNU CC General Public
                     12: License for full details.
                     13: 
                     14: Everyone is granted permission to copy, modify and redistribute
                     15: GNU CC, but only under the conditions described in the
                     16: GNU CC General Public License.   A copy of this license is
                     17: supposed to have been given to you along with GNU CC so you
                     18: can know your rights and responsibilities.  It should be in a
                     19: file named COPYING.  Among other things, the copyright notice
                     20: and this notice must be preserved on all copies.  */
                     21: 
                     22: /* Global variables for machine-dependend things.  */
                     23: 
                     24: /* This should go away if we pass floats to regs via
1.1.1.4   root       25:    the stack instead of the frame, and if we learn how
                     26:    to renumber all the registers when we don't do a save (hard!).  */
1.1       root       27: extern int frame_pointer_needed;
                     28: 
                     29: static rtx find_addr_reg ();
                     30: 
1.1.1.7 ! root       31: /* Return non-zero only if OP is a hard register of mode MODE.  */
        !            32: 
        !            33: static int
        !            34: hardreg (op, mode)
        !            35:      rtx op;
        !            36:      enum machine_mode mode;
        !            37: {
        !            38:   return (REG_P (op) && GET_MODE (op) == mode
        !            39:          && REGNO (op) < FIRST_PSEUDO_REGISTER);
        !            40: }
        !            41: 
1.1.1.4   root       42: /* Return non-zero if this pattern, as a source to a "SET",
                     43:    is known to yield an instruction of unit size.  */
                     44: int
                     45: single_insn_src_p (op, mode)
                     46:      rtx op;
                     47:      enum machine_mode mode;
1.1       root       48: {
1.1.1.4   root       49:   switch (GET_CODE (op))
                     50:     {
                     51:     case CONST_INT:
                     52:       if (SMALL_INT (op))
                     53:        return 1;
                     54:       return 0;
                     55: 
                     56:     case REG:
1.1.1.7 ! root       57:       return 1;
        !            58: 
1.1.1.4   root       59:     case MEM:
1.1.1.7 ! root       60:       if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF)
        !            61:        return 0;
1.1.1.4   root       62:       return 1;
                     63: 
                     64:       /* We never need to negate or complement constants.  */
                     65:     case NOT:
                     66:     case NEG:
                     67:       return 1;
                     68: 
                     69:     case PLUS:
                     70:     case MINUS:
                     71:     case AND:
                     72:     case IOR:
                     73:     case XOR:
                     74:     case LSHIFT:
                     75:     case ASHIFT:
                     76:     case ASHIFTRT:
                     77:     case LSHIFTRT:
                     78:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
                     79:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
                     80:        return 0;
                     81:       return 1;
                     82: 
                     83:     case SUBREG:
                     84:       if (SUBREG_WORD (op) != 0)
                     85:        return 0;
                     86:       return single_insn_src_p (SUBREG_REG (op), mode);
                     87: 
                     88:     case SIGN_EXTEND:
                     89:     case ZERO_EXTEND:
                     90:       /* Lazy... could check for these.  */
                     91:       return 0;
                     92: 
                     93:       /* Not doing floating point, since they probably
                     94:         take longer than the branch slot they might fill.  */
                     95:     case FLOAT_EXTEND:
                     96:     case FLOAT_TRUNCATE:
                     97:     case FLOAT:
                     98:     case FIX:
                     99:     case UNSIGNED_FLOAT:
                    100:     case UNSIGNED_FIX:
                    101:       return 0;
                    102: 
                    103:     default:
                    104:       return 0;
                    105:     }
1.1       root      106: }
1.1.1.4   root      107: 
1.1.1.5   root      108: /* Return truth value of whether OP can be used as an operands in a three
                    109:    address arithmetic insn (such as add %o1,7,%l2) of mode MODE.  */
1.1       root      110: 
                    111: int
                    112: arith_operand (op, mode)
                    113:      rtx op;
                    114:      enum machine_mode mode;
                    115: {
                    116:   return (register_operand (op, mode)
                    117:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
                    118: }
                    119: 
1.1.1.5   root      120: /* Return truth value of whether OP can be used as an operand in a two
                    121:    address arithmetic insn (such as set 123456,%o4) of mode MODE.  */
1.1.1.4   root      122: 
1.1       root      123: int
                    124: arith32_operand (op, mode)
                    125:      rtx op;
                    126:      enum machine_mode mode;
                    127: {
                    128:   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
                    129: }
                    130: 
1.1.1.5   root      131: /* Return truth value of whether OP is a integer which fits the
                    132:    range constraining immediate operands in three-address insns.  */
                    133: 
1.1.1.3   root      134: int
                    135: small_int (op, mode)
                    136:      rtx op;
                    137:      enum machine_mode mode;
                    138: {
                    139:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
                    140: }
                    141: 
1.1       root      142: /* Return the best assembler insn template
                    143:    for moving operands[1] into operands[0] as a fullword.  */
                    144: 
                    145: static char *
                    146: singlemove_string (operands)
                    147:      rtx *operands;
                    148: {
                    149:   if (GET_CODE (operands[0]) == MEM)
                    150:     return "st %r1,%0";
                    151:   if (GET_CODE (operands[1]) == MEM)
                    152:     return "ld %1,%0";
1.1.1.3   root      153:   return "mov %1,%0";
1.1       root      154: }
                    155: 
                    156: /* Output assembler code to perform a doubleword move insn
                    157:    with operands OPERANDS.  */
                    158: 
                    159: char *
                    160: output_move_double (operands)
                    161:      rtx *operands;
                    162: {
                    163:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    164:   rtx latehalf[2];
                    165:   rtx addreg0 = 0, addreg1 = 0;
                    166: 
                    167:   /* First classify both operands.  */
                    168: 
                    169:   if (REG_P (operands[0]))
                    170:     optype0 = REGOP;
                    171:   else if (offsetable_memref_p (operands[0]))
                    172:     optype0 = OFFSOP;
                    173:   else if (GET_CODE (operands[0]) == MEM)
                    174:     optype0 = MEMOP;
                    175:   else
                    176:     optype0 = RNDOP;
                    177: 
                    178:   if (REG_P (operands[1]))
                    179:     optype1 = REGOP;
                    180:   else if (CONSTANT_P (operands[1])
                    181:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    182:     optype1 = CNSTOP;
                    183:   else if (offsetable_memref_p (operands[1]))
                    184:     optype1 = OFFSOP;
                    185:   else if (GET_CODE (operands[1]) == MEM)
1.1.1.7 ! root      186:     optype1 = MEMOP;
1.1       root      187:   else
                    188:     optype1 = RNDOP;
                    189: 
                    190:   /* Check for the cases that the operand constraints are not
                    191:      supposed to allow to happen.  Abort if we get one,
                    192:      because generating code for these cases is painful.  */
                    193: 
                    194:   if (optype0 == RNDOP || optype1 == RNDOP)
                    195:     abort ();
                    196: 
                    197:   /* If an operand is an unoffsettable memory ref, find a register
                    198:      we can increment temporarily to make it refer to the second word.  */
                    199: 
                    200:   if (optype0 == MEMOP)
                    201:     addreg0 = find_addr_reg (operands[0]);
                    202: 
                    203:   if (optype1 == MEMOP)
                    204:     addreg1 = find_addr_reg (operands[1]);
                    205: 
                    206:   /* Ok, we can do one word at a time.
                    207:      Normally we do the low-numbered word first,
                    208:      but if either operand is autodecrementing then we
                    209:      do the high-numbered word first.
                    210: 
                    211:      In either case, set up in LATEHALF the operands to use
                    212:      for the high-numbered word and in some cases alter the
                    213:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    214: 
                    215:   if (optype0 == REGOP)
                    216:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    217:   else if (optype0 == OFFSOP)
                    218:     latehalf[0] = adj_offsetable_operand (operands[0], 4);
                    219:   else
                    220:     latehalf[0] = operands[0];
                    221: 
                    222:   if (optype1 == REGOP)
                    223:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    224:   else if (optype1 == OFFSOP)
                    225:     latehalf[1] = adj_offsetable_operand (operands[1], 4);
                    226:   else if (optype1 == CNSTOP)
                    227:     {
                    228:       if (CONSTANT_P (operands[1]))
                    229:        latehalf[1] = const0_rtx;
                    230:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    231:        {
                    232:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
                    233:          operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
                    234:        }
                    235:     }
                    236:   else
                    237:     latehalf[1] = operands[1];
                    238: 
                    239:   /* If the first move would clobber the source of the second one,
1.1.1.3   root      240:      do them in the other order.
                    241: 
                    242:      RMS says "This happens only for registers;
1.1       root      243:      such overlap can't happen in memory unless the user explicitly
1.1.1.3   root      244:      sets it up, and that is an undefined circumstance."
                    245: 
                    246:      but it happens on the sparc when loading parameter registers,
                    247:      so I am going to define that circumstance, and make it work
                    248:      as expected.  */
                    249: 
                    250:   /* Easy case: try moving both words at once.  */
                    251:   if ((optype0 == REGOP && optype1 != REGOP
                    252:        && (REGNO (operands[0]) & 1) == 0)
                    253:       || (optype0 != REGOP && optype1 == REGOP
                    254:          && (REGNO (operands[1]) & 1) == 0))
                    255:     {
                    256:       rtx op1, op2;
                    257:       rtx base = 0, offset = const0_rtx;
1.1       root      258: 
1.1.1.3   root      259:       if (optype0 == REGOP)
                    260:        op1 = operands[0], op2 = XEXP (operands[1], 0);
                    261:       else
                    262:        op1 = operands[1], op2 = XEXP (operands[0], 0);
                    263: 
1.1.1.4   root      264:       /* Trust global variables.  */
1.1.1.3   root      265:       if (GET_CODE (op2) == SYMBOL_REF
                    266:          || GET_CODE (op2) == CONST
                    267:          || GET_CODE (op2) == REG)
1.1.1.4   root      268:        {
                    269:          if (op1 == operands[0])
                    270:            return "ldd %1,%0";
                    271:          else
                    272:            return "std %1,%0";
                    273:        }
1.1.1.3   root      274: 
1.1.1.4   root      275:       if (GET_CODE (op2) == PLUS)
                    276:        {
                    277:          if (GET_CODE (XEXP (op2, 0)) == REG)
                    278:            base = XEXP (op2, 0), offset = XEXP (op2, 1);
                    279:          else if (GET_CODE (XEXP (op2, 1)) == REG)
                    280:            base = XEXP (op2, 1), offset = XEXP (op2, 0);
                    281:        }
                    282: 
                    283:       /* Trust round enough offsets from the stack or frame pointer.  */
1.1.1.3   root      284:       if (base
1.1.1.4   root      285:          && (REGNO (base) == FRAME_POINTER_REGNUM
                    286:              || REGNO (base) == STACK_POINTER_REGNUM))
                    287:        {
                    288:          if (GET_CODE (offset) == CONST_INT
                    289:              && (INTVAL (offset) & 0x7) == 0)
                    290:            {
                    291:              if (op1 == operands[0])
                    292:                return "ldd %1,%0";
                    293:              else
                    294:                return "std %1,%0";
                    295:            }
                    296:        }
                    297:       else
                    298:        {
                    299:          /* We know structs not on the stack are properly aligned.  */
1.1.1.6   root      300:          if (MEM_IN_STRUCT_P (operands[1]))
1.1.1.4   root      301:            return "ldd %1,%0";
1.1.1.6   root      302:          else if (MEM_IN_STRUCT_P (operands[0]))
1.1.1.4   root      303:            return "std %1,%0";
                    304:        }
1.1.1.3   root      305:     }
1.1.1.4   root      306: 
1.1       root      307:   if (optype0 == REGOP && optype1 == REGOP
                    308:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    309:     {
                    310:       /* Make any unoffsetable addresses point at high-numbered word.  */
                    311:       if (addreg0)
                    312:        output_asm_insn ("add %0,0x4,%0", &addreg0);
                    313:       if (addreg1)
                    314:        output_asm_insn ("add %0,0x4,%0", &addreg1);
                    315: 
                    316:       /* Do that word.  */
                    317:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    318: 
                    319:       /* Undo the adds we just did.  */
                    320:       if (addreg0)
                    321:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    322:       if (addreg1)
                    323:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    324: 
                    325:       /* Do low-numbered word.  */
                    326:       return singlemove_string (operands);
                    327:     }
1.1.1.3   root      328:   else if (optype0 == REGOP && optype1 != REGOP
1.1.1.6   root      329:           && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
1.1.1.3   root      330:     {
                    331:       /* Do the late half first.  */
                    332:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    333:       /* Then clobber.  */
                    334:       return singlemove_string (operands);
                    335:     }
1.1       root      336: 
                    337:   /* Normal case: do the two words, low-numbered first.  */
                    338: 
                    339:   output_asm_insn (singlemove_string (operands), operands);
                    340: 
                    341:   /* Make any unoffsetable addresses point at high-numbered word.  */
                    342:   if (addreg0)
                    343:     output_asm_insn ("add %0,0x4,%0", &addreg0);
                    344:   if (addreg1)
                    345:     output_asm_insn ("add %0,0x4,%0", &addreg1);
                    346: 
                    347:   /* Do that word.  */
                    348:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    349: 
                    350:   /* Undo the adds we just did.  */
                    351:   if (addreg0)
                    352:     output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    353:   if (addreg1)
                    354:     output_asm_insn ("add %0,-0x4,%0", &addreg1);
                    355: 
                    356:   return "";
                    357: }
                    358: 
                    359: static char *
                    360: output_fp_move_double (operands)
                    361:      rtx *operands;
                    362: {
                    363:   if (FP_REG_P (operands[0]))
                    364:     {
                    365:       if (FP_REG_P (operands[1]))
                    366:        {
                    367:          output_asm_insn ("fmovs %1,%0", operands);
                    368:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    369:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    370:          return "fmovs %1,%0";
                    371:        }
                    372:       if (GET_CODE (operands[1]) == REG)
                    373:        {
1.1.1.3   root      374:          if ((REGNO (operands[1]) & 1) == 0)
                    375:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
                    376:          else
                    377:            {
                    378:              rtx xoperands[3];
                    379:              xoperands[0] = operands[0];
                    380:              xoperands[1] = operands[1];
                    381:              xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    382:              output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands);
                    383:              return "";
                    384:            }
1.1       root      385:        }
1.1.1.4   root      386:       if (GET_CODE (XEXP (operands[1], 0)) == PLUS
                    387:          && (XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx
                    388:              || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx)
                    389:          && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT
                    390:          && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) != 0)
                    391:        {
                    392:          rtx xoperands[2];
                    393:          output_asm_insn ("ld %1,%0", operands);
                    394:          xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]),
                    395:                                  REGNO (operands[0]) + 1);
                    396:          xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]),
                    397:                                  plus_constant (XEXP (operands[1], 0), 4));
                    398:          output_asm_insn ("ld %1,%0", xoperands);
                    399:          return "";
                    400:        }
1.1       root      401:       return "ldd %1,%0";
                    402:     }
                    403:   else if (FP_REG_P (operands[1]))
                    404:     {
                    405:       if (GET_CODE (operands[0]) == REG)
                    406:        {
1.1.1.3   root      407:          if ((REGNO (operands[0]) & 1) == 0)
                    408:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
                    409:          else
                    410:            {
                    411:              rtx xoperands[3];
                    412:              xoperands[2] = operands[1];
                    413:              xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    414:              xoperands[0] = operands[0];
                    415:              output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);
                    416:              return "";
                    417:            }
1.1       root      418:        }
1.1.1.4   root      419:       if (GET_CODE (XEXP (operands[0], 0)) == PLUS
                    420:          && (XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx
                    421:              || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx)
                    422:          && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT
                    423:          && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) != 0)
                    424:        {
                    425:          rtx xoperands[2];
                    426:          output_asm_insn ("st %1,%0", operands);
                    427:          xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]),
                    428:                                  REGNO (operands[1]) + 1);
                    429:          xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]),
                    430:                                  plus_constant (XEXP (operands[0], 0), 4));
                    431:          output_asm_insn ("st %1,%0", xoperands);
                    432:          return "";
                    433:        }
1.1       root      434:       return "std %1,%0";
                    435:     }
1.1.1.3   root      436:   else abort ();
1.1       root      437: }
                    438: 
                    439: /* Return a REG that occurs in ADDR with coefficient 1.
                    440:    ADDR can be effectively incremented by incrementing REG.  */
                    441: 
                    442: static rtx
                    443: find_addr_reg (addr)
                    444:      rtx addr;
                    445: {
                    446:   while (GET_CODE (addr) == PLUS)
                    447:     {
                    448:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    449:        addr = XEXP (addr, 0);
                    450:       if (GET_CODE (XEXP (addr, 1)) == REG)
                    451:        addr = XEXP (addr, 1);
                    452:       if (CONSTANT_P (XEXP (addr, 0)))
                    453:        addr = XEXP (addr, 1);
                    454:       if (CONSTANT_P (XEXP (addr, 1)))
                    455:        addr = XEXP (addr, 0);
                    456:     }
                    457:   if (GET_CODE (addr) == REG)
                    458:     return addr;
                    459:   return 0;
                    460: }
                    461: 
                    462: /* Load the address specified by OPERANDS[3] into the register
                    463:    specified by OPERANDS[0].
                    464: 
                    465:    OPERANDS[3] may be the result of a sum, hence it could either be:
                    466: 
                    467:    (1) CONST
                    468:    (2) REG
                    469:    (2) REG + CONST_INT
                    470:    (3) REG + REG + CONST_INT
                    471: 
1.1.1.5   root      472:    Note that (3) is not a legitimate address.
1.1       root      473:    All cases are handled here.  */
                    474: 
                    475: void
                    476: output_load_address (operands)
                    477:      rtx *operands;
                    478: {
                    479:   rtx base, offset;
                    480: 
                    481:   if (CONSTANT_P (operands[3]))
                    482:     {
                    483:       output_asm_insn ("set %3,%0", operands);
                    484:       return;
                    485:     }
                    486: 
                    487:   if (REG_P (operands[3]))
                    488:     {
                    489:       if (REGNO (operands[0]) != REGNO (operands[3]))
                    490:        output_asm_insn ("mov %3,%0", operands);
                    491:       return;
                    492:     }
                    493: 
                    494:   base = XEXP (operands[3], 0);
                    495:   offset = XEXP (operands[3], 1);
                    496: 
                    497:   if (GET_CODE (base) == CONST_INT)
                    498:     {
                    499:       rtx tmp = base;
                    500:       base = offset;
                    501:       offset = tmp;
                    502:     }
                    503: 
                    504:   if (GET_CODE (offset) != CONST_INT)
                    505:     abort ();
                    506: 
                    507:   if (REG_P (base))
                    508:     {
                    509:       operands[6] = base;
                    510:       operands[7] = offset;
                    511:       if (SMALL_INT (offset))
                    512:        output_asm_insn ("add %6,%7,%0", operands);
                    513:       else
                    514:        output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
                    515:     }
                    516:   else
                    517:     {
                    518:       operands[6] = XEXP (base, 0);
                    519:       operands[7] = XEXP (base, 1);
                    520:       operands[8] = offset;
                    521: 
                    522:       if (SMALL_INT (offset))
                    523:        output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
                    524:       else
                    525:        output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
                    526:     }
                    527: }
                    528: 
1.1.1.5   root      529: /* Output code to place a size count SIZE in register REG.
                    530:    If SIZE is round, then assume that we can use alignment
                    531:    based on that roundness, and return an integer saying
                    532:    what alignment (roundness, transfer size) we will be using.
                    533: 
                    534:    Because block moves are pipelined, we don't include the
                    535:    first element in the transfer of SIZE to REG.  */
                    536: 
                    537: static int
                    538: output_size_for_block_move (size, reg)
                    539:      rtx size, reg;
                    540: {
                    541:   int align;
                    542:   rtx xoperands[2];
                    543:   xoperands[0] = reg;
                    544: 
                    545:   /* First, figure out best alignment we may assume.  */
                    546:   if (REG_P (size))
                    547:     {
                    548:       xoperands[1] = size;
                    549:       output_asm_insn ("sub %1,1,%0", xoperands);
                    550:       align = 1;
                    551:     }
                    552:   else
                    553:     {
                    554:       int i = INTVAL (size);
                    555: 
                    556:       if (i & 1)
                    557:        align = 1;
                    558:       else if (i & 3)
                    559:        align = 2;
                    560:       else
                    561:        align = 4;
                    562: 
                    563:       /* predecrement count.  */
                    564:       i -= align;
                    565:       if (i < 0) abort ();
                    566: 
                    567:       xoperands[1] = gen_rtx (CONST_INT, VOIDmode, i);
                    568: 
                    569:       output_asm_insn ("set %1,%0", xoperands);
                    570:     }
                    571:   return align;
                    572: }
                    573: 
                    574: /* Emit code to perform a block move.
                    575: 
                    576:    OPERANDS[0] is the destination.
                    577:    OPERANDS[1] is the source.
                    578:    OPERANDS[2] is the size.
                    579: 
                    580:    We clobber registers 8,9,10, and register 1 (which we
                    581:    do not need to worry about) during this move.
                    582: 
                    583:    It may happen that registers 8,9, and/or 10 are live
                    584:    up to this call, in which case we must be careful
                    585:    to use their values before clobbering them.
                    586: 
                    587:    This function attempts to take advantage of natural
                    588:    luck, such as an operand which is already in an operand
                    589:    register, and hence does not need to be moved around.
                    590: 
                    591:    Perhaps some day, GNU CC will be able to handle dynamic register
                    592:    allocation to such inline library calls.
                    593:    [No, never, because there is already provision for handling
                    594:    library calls at RTL generation time, and I have no interest
                    595:    in maintaining a redundant mechanism for them.
                    596:    I hope some day the movstrsi pattern
                    597:    for sparc will be deleted and an ordinary library call will be
                    598:    used instead.  Then this function will be unnecessary. - rms]  */
                    599: 
                    600: #define COMPATIBLE(REG,OP) \
                    601:   (reg_conflicts[REG].ops[0] == operands[OP]   \
                    602:    && (op_conflicts[OP].n_regs == 0            \
                    603:        || (op_conflicts[OP].n_regs == 1                \
1.1.1.7 ! root      604:           && op_conflicts[OP].regs[0] == REG)  \
        !           605:        || (op_conflicts[OP].n_regs == 2                \
        !           606:           && (op_conflicts[OP].regs[0] == REG  \
        !           607:               || op_conflicts[OP].regs[1] == REG))))
1.1.1.5   root      608: 
1.1       root      609: char *
                    610: output_block_move (operands)
                    611:      rtx *operands;
                    612: {
1.1.1.5   root      613:   /* A vector for our computed operands.  Note that load_output_address
                    614:      makes use of up to the 8th element of this vector.  */
                    615:   rtx xoperands[10];
1.1       root      616:   static int movstrsi_label = 0;
1.1.1.5   root      617:   int align = -1;              /* not yet known */
1.1       root      618:   int i, j;
                    619: 
1.1.1.5   root      620:   /* For each of registers 8, 9, and 10, keep track of
                    621:      which operands use them.  */
                    622:   struct
                    623:     {
                    624:       int n_ops;
                    625:       rtx ops[3];
                    626:     } reg_conflicts[3];
                    627: 
                    628:   /* For each of the 3 operands, keep track of which registers
                    629:      they use.  Each operand can only use 2 registers.  */
                    630:   struct
                    631:     {
                    632:       int n_regs;
                    633:       char regs[2];
                    634:     } op_conflicts[3];
                    635: 
                    636:   /* Make rtxs for the register operands we are using, and
                    637:      initialize all data structures.  */
                    638:   rtx regs[3];
                    639:   rtx reg8 = gen_rtx (REG, SImode, 8);
                    640:   rtx reg9 = gen_rtx (REG, SImode, 9);
                    641:   rtx reg10 = gen_rtx (REG, SImode, 10);
                    642:   regs[0] = reg8;
                    643:   regs[1] = reg9;
                    644:   regs[2] = reg10;
                    645: 
1.1       root      646:   /* Since we clobber untold things, nix the condition codes.  */
                    647:   CC_STATUS_INIT;
                    648: 
1.1.1.5   root      649:   /* Recognize special cases of block moves.  These occur
                    650:      when GNU C++ is forced to treat something as BLKmode
                    651:      to keep it in memory, when its mode could be represented
                    652:      with something smaller.  */
                    653:   if (GET_CODE (operands[2]) == CONST_INT
                    654:       && INTVAL (operands[2]) <= 16)
                    655:     {
                    656:       int size = INTVAL (operands[2]);
                    657:       xoperands[0] = XEXP (operands[0], 0);
                    658:       xoperands[1] = XEXP (operands[1], 0);
                    659:       /* If we are lucky, then this rtx can safely have
                    660:         its INTVAL clobbered.  */
                    661:       xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
                    662: 
                    663:       if (size & 1)
                    664:        {
                    665:          if (memory_address_p (QImode, plus_constant (xoperands[0], size))
                    666:              && memory_address_p (QImode, plus_constant (xoperands[1], size)))
                    667:            {
                    668:              for (i = size-1; i >= 0; i--)
                    669:                {
                    670:                  INTVAL (xoperands[2]) = i;
                    671:                  output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
                    672:                                   xoperands);
                    673:                }
                    674:              return "";
                    675:            }
                    676:        }
                    677:       else if (size & 2)
                    678:        {
                    679:          if (memory_address_p (HImode, plus_constant (xoperands[0], size))
                    680:              && memory_address_p (HImode, plus_constant (xoperands[1], size)))
                    681:            {
                    682:              for (i = (size>>1)-1; i >= 0; i--)
                    683:                {
                    684:                  INTVAL (xoperands[2]) = i<<1;
                    685:                  output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
                    686:                                   xoperands);
                    687:                }
                    688:              return "";
                    689:            }
                    690:        }
                    691:       else
                    692:        {
                    693:          if (memory_address_p (SImode, plus_constant (xoperands[0], size))
                    694:              && memory_address_p (SImode, plus_constant (xoperands[1], size)))
                    695:            {
                    696:              for (i = (size>>2)-1; i >= 0; i--)
                    697:                {
                    698:                  INTVAL (xoperands[2]) = i<<2;
                    699:                  output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
                    700:                                   xoperands);
                    701:                }
                    702:              return "";
                    703:            }
                    704:        }
                    705:     }
                    706: 
                    707:   bzero (reg_conflicts, sizeof (reg_conflicts));
                    708:   bzero (op_conflicts, sizeof (op_conflicts));
1.1.1.6   root      709:   xoperands[0] = 0;
                    710:   xoperands[1] = 0;
                    711:   xoperands[2] = 0;
1.1.1.5   root      712: 
1.1       root      713:   /* Get past the MEMs.  */
                    714:   operands[0] = XEXP (operands[0], 0);
                    715:   operands[1] = XEXP (operands[1], 0);
                    716: 
1.1.1.5   root      717:   /* See which operands use which registers.  */
                    718:   for (i = 0; i < 3; i++)
1.1       root      719:     {
1.1.1.5   root      720:       for (j = 0; j < 3; j++)
                    721:        {
1.1.1.6   root      722:          if (reg_overlap_mentioned_p (regs[i], operands[j]))
1.1.1.5   root      723:            {
                    724:              reg_conflicts[i].ops[reg_conflicts[i].n_ops++] = operands[j];
                    725:              op_conflicts[j].regs[op_conflicts[j].n_regs++] = i;
                    726:            }
                    727:        }
1.1       root      728:     }
1.1.1.5   root      729: 
                    730:   /* We need to know the alignment in order to set up
                    731:      the destination address for a pipelined move.
                    732:      Set it up first, if that is at all easy to do.  */
                    733:   if (op_conflicts[2].n_regs == 0
                    734:       || (op_conflicts[2].n_regs == 1
                    735:          && (reg_conflicts[op_conflicts[2].regs[0]].n_ops == 0
                    736:              || (reg_conflicts[op_conflicts[2].regs[0]].n_ops == 1
                    737:                  && (reg_conflicts[op_conflicts[2].regs[0]].ops[0]
                    738:                      == operands[2])))))
                    739:     {
                    740:       /* This is the size of the transfer.
                    741:          Either use the register which already contains the size,
                    742:         or use a free register (used by no operands).  */
                    743:       rtx reg = op_conflicts[2].n_regs == 1
                    744:        ? regs[op_conflicts[2].regs[0]]
                    745:          : reg_conflicts[0].n_ops == 0
                    746:            ? regs[0]
                    747:              : reg_conflicts[1].n_ops == 0
                    748:                ? regs[1] : regs[2];
                    749: 
                    750:       align = output_size_for_block_move (operands[2], reg);
                    751: 
                    752:       /* Mark this registers as being unavailable.  */
                    753:       reg_conflicts[REGNO (reg) - 8].n_ops = -1;
                    754: 
                    755:       /* Update register usage information for the size operand.  */
                    756:       op_conflicts[2].n_regs = 0;
                    757:       xoperands[2] = reg;
                    758:     }
                    759:      
                    760:   /* If register is used by only one operand,
                    761:      make that register the home for that operand.  */
1.1       root      762:   for (i = 0; i < 3; i++)
                    763:     {
1.1.1.5   root      764:       if (reg_conflicts[i].n_ops == 0)
1.1       root      765:        {
1.1.1.5   root      766:          /* No conflicts for this register.  We can
                    767:             immediately load it with an operand.  Try
                    768:             size first, then source, last dest.  */
                    769:          if (xoperands[2] == 0)
                    770:            {
                    771:              j = 2;
                    772:              /* This is the size of the transfer.  */
                    773:              align = output_size_for_block_move (operands[2], regs[i]);
                    774:              xoperands[2] = regs[i];
                    775:            }
                    776:          else if (xoperands[1] == 0)
                    777:            {
                    778:              /* The source.  */
                    779:              j = 1;
                    780:              xoperands[1] = regs[i];
                    781:              xoperands[4] = operands[1];
                    782:              output_load_address (xoperands + 1);
                    783:            }
                    784:          else
                    785:            {
                    786:              /* The destination.  */
                    787:              j = 0;
                    788:              xoperands[0] = regs[i];
                    789:              xoperands[3] = plus_constant (operands[0], align);
                    790:              output_load_address (xoperands);
                    791:            }
                    792:          /* Mark this register as now unavailable.  */
                    793:          reg_conflicts[i].n_ops = -1;
1.1       root      794:        }
1.1.1.5   root      795:       else if (reg_conflicts[i].n_ops == 1)
1.1       root      796:        {
1.1.1.5   root      797:          /* One conflict.  If the conflict is one which
                    798:             does not clobber anything which depends on this
                    799:             register, go ahead and load the operand
                    800:             into this register.  */
                    801:          if (COMPATIBLE (i, 2))
                    802:            {
                    803:              j = 2;
                    804:              /* This is the size of the transfer.  */
                    805:              align = output_size_for_block_move (operands[2], regs[i]);
                    806:              xoperands[2] = regs[i];
                    807:            }
                    808:          else
                    809:            {
                    810:              /* An address for the transfer.
                    811:                 Set up for pipelined operation: dest must contain
                    812:                 a pre-incremented address, because its index is
                    813:                 pre-decremented.  */
                    814: 
                    815:              if (COMPATIBLE (i, 0))
                    816:                {
                    817:                  /* The destination.  */
                    818:                  if (align < 0)
                    819:                    continue;
                    820:                  j = 0;
                    821:                  xoperands[0] = regs[i];
                    822:                  xoperands[3] = plus_constant (operands[0], align);
                    823:                  output_load_address (xoperands);
                    824:                }
                    825:              else if (COMPATIBLE (i, 1))
                    826:                {
                    827:                  /* The source.  */
                    828:                  j = 1;
                    829:                  xoperands[1] = regs[i];
                    830:                  xoperands[4] = operands[1];
                    831:                  output_load_address (xoperands + 1);
                    832:                }
                    833:              else continue;
                    834:            }
                    835:          /* Mark this register as now unavailable.  */
                    836:          reg_conflicts[i].n_ops = -1;
                    837: 
                    838:          /* Update register usage information for operands.  */
                    839:          op_conflicts[j].n_regs--;
                    840:          if (op_conflicts[j].n_regs && op_conflicts[j].regs[0] == i)
                    841:            op_conflicts[j].regs[0] = op_conflicts[j].regs[1];
1.1       root      842:        }
                    843:     }
                    844: 
1.1.1.5   root      845:   if (xoperands[0] == 0 || xoperands[1] == 0 || xoperands[2] == 0)
1.1       root      846:     {
1.1.1.5   root      847:       /* There were interlocking register requirements.  First
                    848:         user to submit code which triggered that wins a prize.  */
                    849:       abort ();
1.1       root      850:     }
                    851: 
                    852:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                    853:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
                    854: 
1.1.1.5   root      855:   if (align == 1)
                    856:     output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands);
                    857:   else if (align == 2)
                    858:     output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands);
                    859:   else
                    860:     output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands);
1.1       root      861:   return "";
                    862: }
1.1.1.5   root      863: 
                    864: /* What the sparc lacks in hardware, make up for in software.
                    865:    Compute a fairly good sequence of shift and add insns
                    866:    to make a multiply happen.  */
1.1       root      867: 
                    868: #define ABS(x) ((x) < 0 ? -(x) : x)
                    869: 
                    870: char *
                    871: output_mul_by_constant (insn, operands, unsignedp)
                    872:      rtx insn;
                    873:      rtx *operands;
                    874:      int unsignedp;
                    875: {
                    876:   int c;                       /* Size of constant */
                    877:   int shifts[BITS_PER_WORD];   /* Table of shifts */
1.1.1.4   root      878:   unsigned int p, log;         /* A power of two, and its log */
1.1       root      879:   int d1, d2;                  /* Differences of c and p */
                    880:   int first = 1;               /* True if dst has unknown data in it */
                    881:   int i;
                    882: 
                    883:   c = INTVAL (operands[2]);
                    884:   if (c == 0)
                    885:     {
                    886:       /* should not happen.  */
                    887:       abort ();
                    888:       if (GET_CODE (operands[0]) == MEM)
                    889:        return "st %%g0,%0";
                    890:       return "mov %%g0,%0";
                    891:     }
                    892: 
                    893:   output_asm_insn ("! start open coded multiply");
                    894: 
                    895:   /* Clear out the table of shifts. */
                    896:   for (i = 0; i < BITS_PER_WORD; ++i)
                    897:     shifts[i] = 0;
                    898: 
                    899:   while (c)
                    900:     {
                    901:       /* Find the power of two nearest ABS(c) */
                    902:       p = 1, log = 0;
                    903:       do
                    904:        {
                    905:          d1 = ABS(c) - p;
                    906:          p *= 2;
                    907:          ++log;
                    908:        }
                    909:       while (p < ABS(c));
                    910:       d2 = p - ABS(c);
                    911: 
                    912:       /* Make an appropriate entry in shifts for p. */
                    913:       if (d2 < d1)
                    914:        {
                    915:          shifts[log] = c < 0 ? -1 : 1;
                    916:          c = c < 0 ? d2 : -d2;
                    917:        }
                    918:       else
                    919:        {
                    920:          shifts[log - 1] = c < 0 ? -1 : 1;
                    921:          c = c < 0 ? -d1 : d1;
                    922:        }
                    923:     }
                    924: 
                    925:   /* Take care of the first insn in sequence.
                    926:      We know we have at least one. */
                    927: 
                    928:   /* A value of -1 in shifts says to subtract that power of two, and a value
                    929:      of 1 says to add that power of two. */
                    930:   for (i = 0; ; i++)
                    931:     if (shifts[i])
                    932:       {
                    933:        if (i)
                    934:          {
                    935:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i);
1.1.1.5   root      936:            output_asm_insn ("sll %1,%2,%%g1", operands);
1.1       root      937:          }
1.1.1.5   root      938:        else output_asm_insn ("mov %1,%%g1", operands);
1.1       root      939: 
                    940:        log = i;
                    941:        if (shifts[i] < 0)
1.1.1.5   root      942:          output_asm_insn ("sub %%g0,%%g1,%0", operands);
1.1       root      943:        else
1.1.1.5   root      944:          output_asm_insn ("mov %%g1,%0", operands);
1.1       root      945:        break;
                    946:       }
                    947: 
                    948:   /* A value of -1 in shifts says to subtract that power of two, and a value
                    949:      of 1 says to add that power of two--continued.  */
                    950:   for (i += 1; i < BITS_PER_WORD; ++i)
                    951:     if (shifts[i])
                    952:       {
                    953:        if (i - log > 0)
                    954:          {
                    955:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log);
1.1.1.5   root      956:            output_asm_insn ("sll %%g1,%2,%%g1", operands);
1.1       root      957:          }
                    958:        else
                    959:          {
                    960:            operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i);
1.1.1.5   root      961:            output_asm_insn ("sra %%g1,%2,%%g1", operands);
1.1       root      962:          }
                    963:        log = i;
                    964:        if (shifts[i] < 0)
1.1.1.5   root      965:          output_asm_insn ("sub %0,%%g1,%0", operands);
1.1       root      966:        else
1.1.1.5   root      967:          output_asm_insn ("add %0,%%g1,%0", operands);
1.1       root      968:       }
                    969: 
                    970:   output_asm_insn ("! end open coded multiply");
                    971: 
                    972:   return "";
                    973: }
                    974: 
                    975: char *
                    976: output_mul_insn (operands, unsignedp)
                    977:      rtx *operands;
                    978:      int unsignedp;
                    979: {
                    980:   int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1;
                    981:   int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1;
                    982: 
                    983:   if (lucky1)
                    984:     if (lucky2)
                    985:       output_asm_insn ("call .mul,2\n\tnop", operands);
                    986:     else
                    987:       {
                    988:        rtx xoperands[2];
                    989:        xoperands[0] = gen_rtx (REG, SImode,
                    990:                                8 ^ (REGNO (operands[1]) == 8));
                    991:        xoperands[1] = operands[2];
                    992:        output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                    993:       }
                    994:   else if (lucky2)
                    995:     {
                    996:       rtx xoperands[2];
                    997:       xoperands[0] = gen_rtx (REG, SImode,
                    998:                              8 ^ (REGNO (operands[2]) == 8));
                    999:       xoperands[1] = operands[1];
                   1000:       output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                   1001:     }
                   1002:   else
                   1003:     {
                   1004:       output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1",
                   1005:                       operands);
                   1006:     }
                   1007: 
                   1008:   if (REGNO (operands[0]) == 8)
                   1009:     return "";
                   1010:   return "mov %%o0,%0";
                   1011: }
                   1012: 
                   1013: /* Make floating point register f0 contain 0.
                   1014:    SIZE is the number of registers (including f0)
                   1015:    which should contain 0.  */
                   1016: 
                   1017: void
                   1018: make_f0_contain_0 (size)
                   1019:      int size;
                   1020: {
                   1021:   if (size == 1)
1.1.1.3   root     1022:     output_asm_insn ("ld [%%fp-16],%%f0", 0);
1.1       root     1023:   else if (size == 2)
1.1.1.3   root     1024:     output_asm_insn ("ldd [%%fp-16],%%f0", 0);
1.1       root     1025: }
1.1.1.4   root     1026: 
                   1027: /* Output reasonable peephole for set-on-condition-code insns.
                   1028:    Note that these insns assume a particular way of defining
                   1029:    labels.  Therefore, *both* tm-sparc.h and this function must
                   1030:    be changed if a new syntax is needed.  */
                   1031: 
                   1032: char *
                   1033: output_scc_insn (code, operands)
                   1034:      enum rtx_code code;
                   1035:      rtx *operands;
                   1036: {
                   1037:   rtx xoperands[2];
                   1038:   rtx label = gen_label_rtx ();
                   1039: 
                   1040:   xoperands[0] = operands[0];
                   1041:   xoperands[1] = label;
                   1042: 
                   1043:   switch (code)
                   1044:     {
                   1045:     case NE:
                   1046:       if (cc_status.flags & CC_IN_FCCR)
1.1.1.5   root     1047:        output_asm_insn ("fbne,a %l0", &label);
1.1.1.4   root     1048:       else
1.1.1.5   root     1049:        output_asm_insn ("bne,a %l0", &label);
1.1.1.4   root     1050:       break;
                   1051:     case EQ:
                   1052:       if (cc_status.flags & CC_IN_FCCR)
1.1.1.5   root     1053:        output_asm_insn ("fbe,a %l0", &label);
1.1.1.4   root     1054:       else
1.1.1.5   root     1055:        output_asm_insn ("be,a %l0", &label);
1.1.1.4   root     1056:       break;
                   1057:     case GE:
                   1058:       if (cc_status.flags & CC_IN_FCCR)
1.1.1.5   root     1059:        output_asm_insn ("fbge,a %l0", &label);
1.1.1.4   root     1060:       else
1.1.1.5   root     1061:        output_asm_insn ("bge,a %l0", &label);
1.1.1.4   root     1062:       break;
                   1063:     case GT:
                   1064:       if (cc_status.flags & CC_IN_FCCR)
1.1.1.5   root     1065:        output_asm_insn ("fbg,a %l0", &label);
1.1.1.4   root     1066:       else
1.1.1.5   root     1067:        output_asm_insn ("bg,a %l0", &label);
1.1.1.4   root     1068:       break;
                   1069:     case LE:
                   1070:       if (cc_status.flags & CC_IN_FCCR)
1.1.1.5   root     1071:        output_asm_insn ("fble,a %l0", &label);
1.1.1.4   root     1072:       else
1.1.1.5   root     1073:        output_asm_insn ("ble,a %l0", &label);
1.1.1.4   root     1074:       break;
                   1075:     case LT:
                   1076:       if (cc_status.flags & CC_IN_FCCR)
1.1.1.5   root     1077:        output_asm_insn ("fbl,a %l0", &label);
1.1.1.4   root     1078:       else
1.1.1.5   root     1079:        output_asm_insn ("bl,a %l0", &label);
1.1.1.4   root     1080:       break;
                   1081:     case GEU:
                   1082:       if (cc_status.flags & CC_IN_FCCR)
                   1083:        abort ();
                   1084:       else
1.1.1.5   root     1085:        output_asm_insn ("bgeu,a %l0", &label);
1.1.1.4   root     1086:       break;
                   1087:     case GTU:
                   1088:       if (cc_status.flags & CC_IN_FCCR)
                   1089:        abort ();
                   1090:       else
1.1.1.5   root     1091:        output_asm_insn ("bgu,a %l0", &label);
1.1.1.4   root     1092:       break;
                   1093:     case LEU:
                   1094:       if (cc_status.flags & CC_IN_FCCR)
                   1095:        abort ();
                   1096:       else
1.1.1.5   root     1097:        output_asm_insn ("bleu,a %l0", &label);
1.1.1.4   root     1098:       break;
                   1099:     case LTU:
                   1100:       if (cc_status.flags & CC_IN_FCCR)
                   1101:        abort ();
                   1102:       else
1.1.1.5   root     1103:        output_asm_insn ("blu,a %l0", &label);
1.1.1.4   root     1104:       break;
                   1105:     default:
                   1106:       abort ();
                   1107:     }
1.1.1.5   root     1108:   output_asm_insn ("mov 1,%0\n\tmov 0,%0\n%l1", xoperands);
1.1.1.4   root     1109:   return "";
                   1110: }
                   1111: 
1.1.1.5   root     1112: /* Output a delayed branch insn with the delay insn in its
                   1113:    branch slot.  The delayed branch insn template is in TEMPLATE,
                   1114:    with operands OPERANDS.  The insn in its delay slot is INSN.  */
1.1.1.4   root     1115: 
                   1116: char *
                   1117: output_delay_insn (template, operands, insn)
                   1118:      char *template;
                   1119:      rtx *operands;
                   1120:      rtx insn;
                   1121: {
                   1122:   extern char *insn_template[];
                   1123:   extern char *(*insn_outfun[])();
                   1124:   rtx pat = gen_rtx (SET, VOIDmode,
                   1125:                     XVECEXP (PATTERN (insn), 0, 0),
                   1126:                     XVECEXP (PATTERN (insn), 0, 1));
                   1127:   rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
                   1128:   int insn_code_number;
                   1129: 
                   1130:   /* Output the branch instruction first.  */
                   1131:   output_asm_insn (template, operands);
                   1132: 
                   1133:   /* Now recognize the insn which we put in its delay slot.
                   1134:      We must do this after outputing the branch insn,
                   1135:      since operands may just be a pointer to `recog_operands'.  */
                   1136:   insn_code_number = recog (pat, delay_insn);
                   1137:   if (insn_code_number == -1)
                   1138:     abort ();
                   1139: 
                   1140:   /* Now get the template for what this insn would
                   1141:      have been, without the branch.  Its operands are
                   1142:      exactly the same as they would be, so we don't
                   1143:      need to do an insn_extract.  */
                   1144:   template = insn_template[insn_code_number];
                   1145:   if (template == 0)
                   1146:     template = (*insn_outfun[insn_code_number]) (operands, delay_insn);
                   1147:   output_asm_insn (template, operands);
                   1148:   return "";
                   1149: }

unix.superglobalmegacorp.com

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