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

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

unix.superglobalmegacorp.com

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