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

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

unix.superglobalmegacorp.com

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