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

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: 
        !            93: /* ??? Comment needed here */
1.1       root       94: 
                     95: int
                     96: arith_operand (op, mode)
                     97:      rtx op;
                     98:      enum machine_mode mode;
                     99: {
                    100:   return (register_operand (op, mode)
                    101:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
                    102: }
                    103: 
1.1.1.4 ! root      104: /* ??? Comment needed here */
        !           105: 
1.1       root      106: int
                    107: arith32_operand (op, mode)
                    108:      rtx op;
                    109:      enum machine_mode mode;
                    110: {
                    111:   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
                    112: }
                    113: 
1.1.1.3   root      114: int
                    115: small_int (op, mode)
                    116:      rtx op;
                    117:      enum machine_mode mode;
                    118: {
                    119:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
                    120: }
                    121: 
1.1       root      122: /* Return the best assembler insn template
                    123:    for moving operands[1] into operands[0] as a fullword.  */
                    124: 
                    125: static char *
                    126: singlemove_string (operands)
                    127:      rtx *operands;
                    128: {
                    129:   if (GET_CODE (operands[0]) == MEM)
                    130:     return "st %r1,%0";
                    131:   if (GET_CODE (operands[1]) == MEM)
                    132:     return "ld %1,%0";
1.1.1.3   root      133:   return "mov %1,%0";
1.1       root      134: }
                    135: 
                    136: /* Output assembler code to perform a doubleword move insn
                    137:    with operands OPERANDS.  */
                    138: 
                    139: char *
                    140: output_move_double (operands)
                    141:      rtx *operands;
                    142: {
                    143:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    144:   rtx latehalf[2];
                    145:   rtx addreg0 = 0, addreg1 = 0;
                    146: 
                    147:   /* First classify both operands.  */
                    148: 
                    149:   if (REG_P (operands[0]))
                    150:     optype0 = REGOP;
                    151:   else if (offsetable_memref_p (operands[0]))
                    152:     optype0 = OFFSOP;
                    153:   else if (GET_CODE (operands[0]) == MEM)
                    154:     optype0 = MEMOP;
                    155:   else
                    156:     optype0 = RNDOP;
                    157: 
                    158:   if (REG_P (operands[1]))
                    159:     optype1 = REGOP;
                    160:   else if (CONSTANT_P (operands[1])
                    161:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    162:     optype1 = CNSTOP;
                    163:   else if (offsetable_memref_p (operands[1]))
                    164:     optype1 = OFFSOP;
                    165:   else if (GET_CODE (operands[1]) == MEM)
                    166:     optype0 = MEMOP;
                    167:   else
                    168:     optype1 = RNDOP;
                    169: 
                    170:   /* Check for the cases that the operand constraints are not
                    171:      supposed to allow to happen.  Abort if we get one,
                    172:      because generating code for these cases is painful.  */
                    173: 
                    174:   if (optype0 == RNDOP || optype1 == RNDOP)
                    175:     abort ();
                    176: 
                    177:   /* If an operand is an unoffsettable memory ref, find a register
                    178:      we can increment temporarily to make it refer to the second word.  */
                    179: 
                    180:   if (optype0 == MEMOP)
                    181:     addreg0 = find_addr_reg (operands[0]);
                    182: 
                    183:   if (optype1 == MEMOP)
                    184:     addreg1 = find_addr_reg (operands[1]);
                    185: 
                    186:   /* Ok, we can do one word at a time.
                    187:      Normally we do the low-numbered word first,
                    188:      but if either operand is autodecrementing then we
                    189:      do the high-numbered word first.
                    190: 
                    191:      In either case, set up in LATEHALF the operands to use
                    192:      for the high-numbered word and in some cases alter the
                    193:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    194: 
                    195:   if (optype0 == REGOP)
                    196:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    197:   else if (optype0 == OFFSOP)
                    198:     latehalf[0] = adj_offsetable_operand (operands[0], 4);
                    199:   else
                    200:     latehalf[0] = operands[0];
                    201: 
                    202:   if (optype1 == REGOP)
                    203:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    204:   else if (optype1 == OFFSOP)
                    205:     latehalf[1] = adj_offsetable_operand (operands[1], 4);
                    206:   else if (optype1 == CNSTOP)
                    207:     {
                    208:       if (CONSTANT_P (operands[1]))
                    209:        latehalf[1] = const0_rtx;
                    210:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    211:        {
                    212:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
                    213:          operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
                    214:        }
                    215:     }
                    216:   else
                    217:     latehalf[1] = operands[1];
                    218: 
                    219:   /* If the first move would clobber the source of the second one,
1.1.1.3   root      220:      do them in the other order.
                    221: 
                    222:      RMS says "This happens only for registers;
1.1       root      223:      such overlap can't happen in memory unless the user explicitly
1.1.1.3   root      224:      sets it up, and that is an undefined circumstance."
                    225: 
                    226:      but it happens on the sparc when loading parameter registers,
                    227:      so I am going to define that circumstance, and make it work
                    228:      as expected.  */
                    229: 
                    230:   /* Easy case: try moving both words at once.  */
                    231:   if ((optype0 == REGOP && optype1 != REGOP
                    232:        && (REGNO (operands[0]) & 1) == 0)
                    233:       || (optype0 != REGOP && optype1 == REGOP
                    234:          && (REGNO (operands[1]) & 1) == 0))
                    235:     {
                    236:       rtx op1, op2;
                    237:       rtx base = 0, offset = const0_rtx;
1.1       root      238: 
1.1.1.3   root      239:       if (optype0 == REGOP)
                    240:        op1 = operands[0], op2 = XEXP (operands[1], 0);
                    241:       else
                    242:        op1 = operands[1], op2 = XEXP (operands[0], 0);
                    243: 
1.1.1.4 ! root      244:       /* Trust global variables.  */
1.1.1.3   root      245:       if (GET_CODE (op2) == SYMBOL_REF
                    246:          || GET_CODE (op2) == CONST
                    247:          || GET_CODE (op2) == REG)
1.1.1.4 ! root      248:        {
        !           249:          if (op1 == operands[0])
        !           250:            return "ldd %1,%0";
        !           251:          else
        !           252:            return "std %1,%0";
        !           253:        }
1.1.1.3   root      254: 
1.1.1.4 ! root      255:       if (GET_CODE (op2) == PLUS)
        !           256:        {
        !           257:          if (GET_CODE (XEXP (op2, 0)) == REG)
        !           258:            base = XEXP (op2, 0), offset = XEXP (op2, 1);
        !           259:          else if (GET_CODE (XEXP (op2, 1)) == REG)
        !           260:            base = XEXP (op2, 1), offset = XEXP (op2, 0);
        !           261:        }
        !           262: 
        !           263:       /* Trust round enough offsets from the stack or frame pointer.  */
1.1.1.3   root      264:       if (base
1.1.1.4 ! root      265:          && (REGNO (base) == FRAME_POINTER_REGNUM
        !           266:              || REGNO (base) == STACK_POINTER_REGNUM))
        !           267:        {
        !           268:          if (GET_CODE (offset) == CONST_INT
        !           269:              && (INTVAL (offset) & 0x7) == 0)
        !           270:            {
        !           271:              if (op1 == operands[0])
        !           272:                return "ldd %1,%0";
        !           273:              else
        !           274:                return "std %1,%0";
        !           275:            }
        !           276:        }
        !           277:       else
        !           278:        {
        !           279:          /* We know structs not on the stack are properly aligned.  */
        !           280:          if (operands[1]->in_struct)
        !           281:            return "ldd %1,%0";
        !           282:          else if (operands[0]->in_struct)
        !           283:            return "std %1,%0";
        !           284:        }
1.1.1.3   root      285:     }
1.1.1.4 ! root      286: 
1.1       root      287:   if (optype0 == REGOP && optype1 == REGOP
                    288:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    289:     {
                    290:       /* Make any unoffsetable addresses point at high-numbered word.  */
                    291:       if (addreg0)
                    292:        output_asm_insn ("add %0,0x4,%0", &addreg0);
                    293:       if (addreg1)
                    294:        output_asm_insn ("add %0,0x4,%0", &addreg1);
                    295: 
                    296:       /* Do that word.  */
                    297:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    298: 
                    299:       /* Undo the adds we just did.  */
                    300:       if (addreg0)
                    301:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    302:       if (addreg1)
                    303:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    304: 
                    305:       /* Do low-numbered word.  */
                    306:       return singlemove_string (operands);
                    307:     }
1.1.1.3   root      308:   else if (optype0 == REGOP && optype1 != REGOP
                    309:           && reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
                    310:     {
                    311:       /* Do the late half first.  */
                    312:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    313:       /* Then clobber.  */
                    314:       return singlemove_string (operands);
                    315:     }
1.1       root      316: 
                    317:   /* Normal case: do the two words, low-numbered first.  */
                    318: 
                    319:   output_asm_insn (singlemove_string (operands), operands);
                    320: 
                    321:   /* Make any unoffsetable addresses point at high-numbered word.  */
                    322:   if (addreg0)
                    323:     output_asm_insn ("add %0,0x4,%0", &addreg0);
                    324:   if (addreg1)
                    325:     output_asm_insn ("add %0,0x4,%0", &addreg1);
                    326: 
                    327:   /* Do that word.  */
                    328:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    329: 
                    330:   /* Undo the adds we just did.  */
                    331:   if (addreg0)
                    332:     output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    333:   if (addreg1)
                    334:     output_asm_insn ("add %0,-0x4,%0", &addreg1);
                    335: 
                    336:   return "";
                    337: }
                    338: 
                    339: static char *
                    340: output_fp_move_double (operands)
                    341:      rtx *operands;
                    342: {
                    343:   if (FP_REG_P (operands[0]))
                    344:     {
                    345:       if (FP_REG_P (operands[1]))
                    346:        {
                    347:          output_asm_insn ("fmovs %1,%0", operands);
                    348:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    349:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    350:          return "fmovs %1,%0";
                    351:        }
                    352:       if (GET_CODE (operands[1]) == REG)
                    353:        {
1.1.1.3   root      354:          if ((REGNO (operands[1]) & 1) == 0)
                    355:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
                    356:          else
                    357:            {
                    358:              rtx xoperands[3];
                    359:              xoperands[0] = operands[0];
                    360:              xoperands[1] = operands[1];
                    361:              xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    362:              output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands);
                    363:              return "";
                    364:            }
1.1       root      365:        }
1.1.1.4 ! root      366:       if (GET_CODE (XEXP (operands[1], 0)) == PLUS
        !           367:          && (XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx
        !           368:              || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx)
        !           369:          && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT
        !           370:          && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) != 0)
        !           371:        {
        !           372:          rtx xoperands[2];
        !           373:          output_asm_insn ("ld %1,%0", operands);
        !           374:          xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]),
        !           375:                                  REGNO (operands[0]) + 1);
        !           376:          xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]),
        !           377:                                  plus_constant (XEXP (operands[1], 0), 4));
        !           378:          output_asm_insn ("ld %1,%0", xoperands);
        !           379:          return "";
        !           380:        }
1.1       root      381:       return "ldd %1,%0";
                    382:     }
                    383:   else if (FP_REG_P (operands[1]))
                    384:     {
                    385:       if (GET_CODE (operands[0]) == REG)
                    386:        {
1.1.1.3   root      387:          if ((REGNO (operands[0]) & 1) == 0)
                    388:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
                    389:          else
                    390:            {
                    391:              rtx xoperands[3];
                    392:              xoperands[2] = operands[1];
                    393:              xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    394:              xoperands[0] = operands[0];
                    395:              output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);
                    396:              return "";
                    397:            }
1.1       root      398:        }
1.1.1.4 ! root      399:       if (GET_CODE (XEXP (operands[0], 0)) == PLUS
        !           400:          && (XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx
        !           401:              || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx)
        !           402:          && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT
        !           403:          && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) != 0)
        !           404:        {
        !           405:          rtx xoperands[2];
        !           406:          output_asm_insn ("st %1,%0", operands);
        !           407:          xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]),
        !           408:                                  REGNO (operands[1]) + 1);
        !           409:          xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]),
        !           410:                                  plus_constant (XEXP (operands[0], 0), 4));
        !           411:          output_asm_insn ("st %1,%0", xoperands);
        !           412:          return "";
        !           413:        }
1.1       root      414:       return "std %1,%0";
                    415:     }
1.1.1.3   root      416:   else abort ();
1.1       root      417: }
                    418: 
                    419: /* Return a REG that occurs in ADDR with coefficient 1.
                    420:    ADDR can be effectively incremented by incrementing REG.  */
                    421: 
                    422: static rtx
                    423: find_addr_reg (addr)
                    424:      rtx addr;
                    425: {
                    426:   while (GET_CODE (addr) == PLUS)
                    427:     {
                    428:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    429:        addr = XEXP (addr, 0);
                    430:       if (GET_CODE (XEXP (addr, 1)) == REG)
                    431:        addr = XEXP (addr, 1);
                    432:       if (CONSTANT_P (XEXP (addr, 0)))
                    433:        addr = XEXP (addr, 1);
                    434:       if (CONSTANT_P (XEXP (addr, 1)))
                    435:        addr = XEXP (addr, 0);
                    436:     }
                    437:   if (GET_CODE (addr) == REG)
                    438:     return addr;
                    439:   return 0;
                    440: }
                    441: 
                    442: /* Load the address specified by OPERANDS[3] into the register
                    443:    specified by OPERANDS[0].
                    444: 
                    445:    OPERANDS[3] may be the result of a sum, hence it could either be:
                    446: 
                    447:    (1) CONST
                    448:    (2) REG
                    449:    (2) REG + CONST_INT
                    450:    (3) REG + REG + CONST_INT
                    451: 
                    452:    All cases are handled here.  */
                    453: 
                    454: void
                    455: output_load_address (operands)
                    456:      rtx *operands;
                    457: {
                    458:   rtx base, offset;
                    459: 
                    460:   if (CONSTANT_P (operands[3]))
                    461:     {
                    462:       output_asm_insn ("set %3,%0", operands);
                    463:       return;
                    464:     }
                    465: 
                    466:   if (REG_P (operands[3]))
                    467:     {
                    468:       if (REGNO (operands[0]) != REGNO (operands[3]))
                    469:        output_asm_insn ("mov %3,%0", operands);
                    470:       return;
                    471:     }
                    472: 
                    473:   base = XEXP (operands[3], 0);
                    474:   offset = XEXP (operands[3], 1);
                    475: 
                    476:   if (GET_CODE (base) == CONST_INT)
                    477:     {
                    478:       rtx tmp = base;
                    479:       base = offset;
                    480:       offset = tmp;
                    481:     }
                    482: 
                    483:   if (GET_CODE (offset) != CONST_INT)
                    484:     abort ();
                    485: 
                    486:   if (REG_P (base))
                    487:     {
                    488:       operands[6] = base;
                    489:       operands[7] = offset;
                    490:       if (SMALL_INT (offset))
                    491:        output_asm_insn ("add %6,%7,%0", operands);
                    492:       else
                    493:        output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
                    494:     }
                    495:   else
                    496:     {
                    497:       operands[6] = XEXP (base, 0);
                    498:       operands[7] = XEXP (base, 1);
                    499:       operands[8] = offset;
                    500: 
                    501:       if (SMALL_INT (offset))
                    502:        output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
                    503:       else
                    504:        output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
                    505:     }
                    506: }
                    507: 
                    508: char *
                    509: output_block_move (operands)
                    510:      rtx *operands;
                    511: {
                    512:   static int movstrsi_label = 0;
                    513:   int align = 4;
                    514: 
                    515:   rtx xoperands[9];
                    516:   int available[3];
                    517:   int i, j;
                    518: 
                    519:   /* Since we clobber untold things, nix the condition codes.  */
                    520:   CC_STATUS_INIT;
                    521: 
                    522:   /* Get past the MEMs.  */
                    523:   operands[0] = XEXP (operands[0], 0);
                    524:   operands[1] = XEXP (operands[1], 0);
                    525: 
                    526:   xoperands[0] = 0;
                    527:   xoperands[1] = 0;
                    528:   xoperands[2] = 0;
                    529: 
                    530:   available[0] = 1;
                    531:   available[1] = 1;
                    532:   available[2] = 1;
                    533: #if 1
                    534:   /* Prepare to juggle registers if necessary.  */
                    535:   if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 8) < 3)
                    536:     {
                    537:       xoperands[0] = operands[0];
                    538:       available[REGNO (operands[0]) - 8] = 0;
                    539:     }
                    540:   if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 8) < 3)
                    541:     {
                    542:       xoperands[1] = operands[1];
                    543:       available[REGNO (operands[1]) - 8] = 0;
                    544:     }
                    545:   if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 8) < 3)
                    546:     {
                    547:       xoperands[2] = operands[2];
                    548:       available[REGNO (operands[2]) - 8] = 0;
                    549:     }
                    550:   for (i = 0; i < 3; i++)
                    551:     {
                    552:       if (xoperands[i])
                    553:        continue;
                    554:       if (available[0])
                    555:        {
                    556:          xoperands[i] = gen_rtx (REG, SImode, 8);
                    557:          available[0] = 0;
                    558:          continue;
                    559:        }
                    560:       if (available[1])
                    561:        {
                    562:          xoperands[i] = gen_rtx (REG, SImode, 9);
                    563:          available[1] = 0;
                    564:          continue;
                    565:        }
                    566:       xoperands[i] = gen_rtx (REG, SImode, 10);
                    567:       available[2] = 0;
                    568:     }
                    569: #endif
                    570: 
                    571:   /* First, figure out best alignment we may assume.  */
                    572:   if (REG_P (operands[2]))
                    573:     {
                    574:       xoperands[5] = operands[2];
                    575:       output_asm_insn ("sub %5,0x1,%2", xoperands);
                    576:       align = 1;
                    577:     }
                    578:   else
                    579:     {
                    580:       int i = INTVAL (operands[2]);
                    581: 
                    582:       if (i & 1)
                    583:        align = 1;
                    584:       else if (i & 3)
                    585:        align = 2;
                    586: 
                    587:       /* predecrement count.  */
                    588:       i -= align;
                    589:       if (i < 0) abort ();
                    590: 
                    591:       xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i);
                    592: 
                    593:       output_asm_insn ("set %5,%2", xoperands);
                    594:     }
                    595: 
                    596:   /* Now, set up for pipelined operation: dest must contain
                    597:      a pre-incremented address, because its index is pre-decremented.  */
                    598: 
                    599:   xoperands[3] = plus_constant (operands[0], align);
                    600:   output_load_address (xoperands);
                    601: 
                    602:   xoperands[4] = operands[1];
                    603:   output_load_address (xoperands+1);
                    604: 
                    605:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                    606:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
                    607: 
1.1.1.4 ! root      608:   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      609:   return "";
                    610: }
                    611: 
                    612: #define ABS(x) ((x) < 0 ? -(x) : x)
                    613: 
                    614: char *
                    615: output_mul_by_constant (insn, operands, unsignedp)
                    616:      rtx insn;
                    617:      rtx *operands;
                    618:      int unsignedp;
                    619: {
                    620:   int c;                       /* Size of constant */
                    621:   int shifts[BITS_PER_WORD];   /* Table of shifts */
1.1.1.4 ! root      622:   unsigned int p, log;         /* A power of two, and its log */
1.1       root      623:   int d1, d2;                  /* Differences of c and p */
                    624:   int first = 1;               /* True if dst has unknown data in it */
                    625:   int i;
                    626: 
                    627:   c = INTVAL (operands[2]);
                    628:   if (c == 0)
                    629:     {
                    630:       /* should not happen.  */
                    631:       abort ();
                    632:       if (GET_CODE (operands[0]) == MEM)
                    633:        return "st %%g0,%0";
                    634:       return "mov %%g0,%0";
                    635:     }
                    636: 
                    637: #if 0
                    638:   printf ("open coding insn:\n");
                    639:   debug_rtx (insn);
                    640:   printf ("done.\n");
                    641: #endif
                    642: 
                    643:   output_asm_insn ("! start open coded multiply");
                    644: 
                    645:   /* Clear out the table of shifts. */
                    646:   for (i = 0; i < BITS_PER_WORD; ++i)
                    647:     shifts[i] = 0;
                    648: 
                    649:   while (c)
                    650:     {
                    651:       /* Find the power of two nearest ABS(c) */
                    652:       p = 1, log = 0;
                    653:       do
                    654:        {
                    655:          d1 = ABS(c) - p;
                    656:          p *= 2;
                    657:          ++log;
                    658:        }
                    659:       while (p < ABS(c));
                    660:       d2 = p - ABS(c);
                    661: 
                    662:       /* Make an appropriate entry in shifts for p. */
                    663:       if (d2 < d1)
                    664:        {
                    665:          shifts[log] = c < 0 ? -1 : 1;
                    666:          c = c < 0 ? d2 : -d2;
                    667:        }
                    668:       else
                    669:        {
                    670:          shifts[log - 1] = c < 0 ? -1 : 1;
                    671:          c = c < 0 ? -d1 : d1;
                    672:        }
                    673:     }
                    674: 
                    675:   /* For now, use a known clobberable register.  This could
                    676:      be improved by looking at insn, and seeing if we
                    677:      have a dying register contained therein.  */
                    678:   regs_ever_live[15] = 1;
                    679:   operands[3] = gen_rtx (REG, SImode, 15);
                    680: 
                    681:   /* Take care of the first insn in sequence.
                    682:      We know we have at least one. */
                    683: 
                    684:   /* A value of -1 in shifts says to subtract that power of two, and a value
                    685:      of 1 says to add that power of two. */
                    686:   for (i = 0; ; i++)
                    687:     if (shifts[i])
                    688:       {
                    689:        if (i)
                    690:          {
                    691:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i);
                    692:            output_asm_insn ("sll %1,%2,%3", operands);
                    693:          }
                    694:        else if (REGNO (operands[3]) == 15)
                    695:          output_asm_insn ("mov %1,%3", operands);
                    696: 
                    697:        log = i;
                    698:        if (shifts[i] < 0)
                    699:          output_asm_insn ("sub %%g0,%3,%0", operands);
                    700:        else
                    701:          output_asm_insn ("mov %3,%0", operands);
                    702:        break;
                    703:       }
                    704: 
                    705:   /* A value of -1 in shifts says to subtract that power of two, and a value
                    706:      of 1 says to add that power of two--continued.  */
                    707:   for (i += 1; i < BITS_PER_WORD; ++i)
                    708:     if (shifts[i])
                    709:       {
                    710:        if (i - log > 0)
                    711:          {
                    712:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log);
                    713:            output_asm_insn ("sll %3,%2,%3", operands);
                    714:          }
                    715:        else
                    716:          {
                    717:            operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i);
                    718:            output_asm_insn ("sra %3,%2,%3", operands);
                    719:          }
                    720:        log = i;
                    721:        if (shifts[i] < 0)
                    722:          output_asm_insn ("sub %0,%3,%0", operands);
                    723:        else
                    724:          output_asm_insn ("add %0,%3,%0", operands);
                    725:       }
                    726: 
                    727:   output_asm_insn ("! end open coded multiply");
                    728: 
                    729:   return "";
                    730: }
                    731: 
                    732: char *
                    733: output_mul_insn (operands, unsignedp)
                    734:      rtx *operands;
                    735:      int unsignedp;
                    736: {
                    737:   int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1;
                    738:   int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1;
                    739: 
                    740:   if (lucky1)
                    741:     if (lucky2)
                    742:       output_asm_insn ("call .mul,2\n\tnop", operands);
                    743:     else
                    744:       {
                    745:        rtx xoperands[2];
                    746:        xoperands[0] = gen_rtx (REG, SImode,
                    747:                                8 ^ (REGNO (operands[1]) == 8));
                    748:        xoperands[1] = operands[2];
                    749:        output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                    750:       }
                    751:   else if (lucky2)
                    752:     {
                    753:       rtx xoperands[2];
                    754:       xoperands[0] = gen_rtx (REG, SImode,
                    755:                              8 ^ (REGNO (operands[2]) == 8));
                    756:       xoperands[1] = operands[1];
                    757:       output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                    758:     }
                    759:   else
                    760:     {
                    761:       output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1",
                    762:                       operands);
                    763:     }
                    764: 
                    765:   if (REGNO (operands[0]) == 8)
                    766:     return "";
                    767:   return "mov %%o0,%0";
                    768: }
                    769: 
                    770: #if 0
                    771: /* This function does not properly protect its operands.  */
                    772: char *
                    773: output_arith_insn (operands, name)
                    774:      rtx *operands;
                    775:      char *name;
                    776: {
                    777:   extern struct _iobuf *asm_out_file;
                    778: 
                    779:   /* Does not commute.  */
                    780:   rtx op1 = 0;
                    781:   rtx op2 = 0;
                    782: 
                    783:   abort ();
                    784:   if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 8)
                    785:     op1 = operands[1];
                    786:   if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 8)
                    787:     op2 = operands[2];
                    788: 
                    789:   if (op1 && op2)
                    790:     {
                    791:       /* ?? should have been done earlier.  */
                    792:       abort ();
                    793:     }
                    794:   else
                    795:     {
                    796:       if (op2)
                    797:        {
                    798:          op1 = operands[1];
                    799:          if (REG_P (op1) && REGNO (op1) == 9)
                    800:            {
                    801:              output_asm_insn ("mov %%o1,%%o2\n\tmov %%o0,%%o1", operands);
                    802:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    803:              output_asm_insn ("mov %%o2,%%o0", operands);
                    804:              goto done;
                    805:            }
                    806:          output_asm_insn ("mov %%o0,%%o1", operands);
                    807:          if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1))
                    808:            {
                    809:              output_asm_insn ("sethi %%hi(%1),%%o0", operands);
                    810:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    811:              output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands);
                    812:            }
                    813:          else
                    814:            {
                    815:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    816:              if (GET_CODE (op1) == MEM)
                    817:                output_asm_insn ("ld %1,%%o0", operands);
                    818:              else
                    819:                output_asm_insn ("mov %1,%%o0", operands);
                    820:            }
                    821:        }
                    822:       else if (op1)
                    823:        {
                    824:          op2 = operands[2];
                    825:          if (REG_P (op2) && REGNO (operands[1]) == 9)
                    826:            {
                    827:              fprintf (asm_out_file, "\tcall %s,2\n\tnop\n");
                    828:              goto done;
                    829:            }
                    830:          if (GET_CODE (op2) == CONST_INT && ! SMALL_INT (op2))
                    831:            {
                    832:              output_asm_insn ("sethi %%hi(%2),%%o1", operands);
                    833:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    834:              output_asm_insn ("add %%o1,%%lo(%2),%%o1", operands);
                    835:            }
                    836:          else
                    837:            {
                    838:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    839:              if (GET_CODE (op2) == MEM)
                    840:                output_asm_insn ("ld %2,%%o1", operands);
                    841:              else
                    842:                output_asm_insn ("mov %2,%%o1", operands);
                    843:            }
                    844:        }
                    845:       else
                    846:        {
                    847:          op1 = operands[1];
                    848:          op2 = operands[2];
                    849: 
                    850:          if (! REG_P (op2) || REGNO (op2) != 9)
                    851:            if (GET_CODE (op2) == MEM)
                    852:              output_asm_insn ("ld %2,%%o1", operands);
                    853:            else if (GET_CODE (op2) != CONST_INT || SMALL_INT (op2))
                    854:              output_asm_insn ("mov %2,%%o1", operands);
                    855:            else
                    856:              output_asm_insn ("sethi %%hi(%2),%%o1\n\tadd %%o1,%%lo(%2),%%o1", operands);
                    857:          if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1))
                    858:            {
                    859:              output_asm_insn ("sethi %%hi(%1),%%o0", operands);
                    860:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    861:              output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands);
                    862:            }
                    863:          else
                    864:            {
                    865:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    866:              if (GET_CODE (op1) == MEM)
                    867:                output_asm_insn ("ld %1,%%o0", operands);
                    868:              else
                    869:                output_asm_insn ("mov %1,%%o0", operands);
                    870:            }
                    871:        }
                    872:     done:
                    873:       if (REG_P (operands[0]) && REGNO (operands[0]) == 8)
                    874:        return "";
                    875:       if (GET_CODE (operands[0]) == MEM)
                    876:        return "st %%o0,%0";
                    877:       return "mov %%o0,%0";
                    878:     }
                    879: }
                    880: #endif
                    881: 
                    882: /* Make floating point register f0 contain 0.
                    883:    SIZE is the number of registers (including f0)
                    884:    which should contain 0.  */
                    885: 
                    886: void
                    887: make_f0_contain_0 (size)
                    888:      int size;
                    889: {
                    890:   if (size == 1)
1.1.1.3   root      891:     output_asm_insn ("ld [%%fp-16],%%f0", 0);
1.1       root      892:   else if (size == 2)
1.1.1.3   root      893:     output_asm_insn ("ldd [%%fp-16],%%f0", 0);
1.1       root      894: }
1.1.1.4 ! root      895: 
        !           896: /* Output reasonable peephole for set-on-condition-code insns.
        !           897:    Note that these insns assume a particular way of defining
        !           898:    labels.  Therefore, *both* tm-sparc.h and this function must
        !           899:    be changed if a new syntax is needed.  */
        !           900: 
        !           901: char *
        !           902: output_scc_insn (code, operands)
        !           903:      enum rtx_code code;
        !           904:      rtx *operands;
        !           905: {
        !           906:   rtx xoperands[2];
        !           907:   rtx label = gen_label_rtx ();
        !           908: 
        !           909:   xoperands[0] = operands[0];
        !           910:   xoperands[1] = label;
        !           911: 
        !           912:   switch (code)
        !           913:     {
        !           914:     case NE:
        !           915:       if (cc_status.flags & CC_IN_FCCR)
        !           916:        output_asm_insn ("fbne,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           917:       else
        !           918:        output_asm_insn ("bne,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           919:       break;
        !           920:     case EQ:
        !           921:       if (cc_status.flags & CC_IN_FCCR)
        !           922:        output_asm_insn ("fbe,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           923:       else
        !           924:        output_asm_insn ("be,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           925:       break;
        !           926:     case GE:
        !           927:       if (cc_status.flags & CC_IN_FCCR)
        !           928:        output_asm_insn ("fbge,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           929:       else
        !           930:        output_asm_insn ("bge,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           931:       break;
        !           932:     case GT:
        !           933:       if (cc_status.flags & CC_IN_FCCR)
        !           934:        output_asm_insn ("fbg,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           935:       else
        !           936:        output_asm_insn ("bg,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           937:       break;
        !           938:     case LE:
        !           939:       if (cc_status.flags & CC_IN_FCCR)
        !           940:        output_asm_insn ("fble,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           941:       else
        !           942:        output_asm_insn ("ble,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           943:       break;
        !           944:     case LT:
        !           945:       if (cc_status.flags & CC_IN_FCCR)
        !           946:        output_asm_insn ("fbl,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           947:       else
        !           948:        output_asm_insn ("bl,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           949:       break;
        !           950:     case GEU:
        !           951:       if (cc_status.flags & CC_IN_FCCR)
        !           952:        abort ();
        !           953:       else
        !           954:        output_asm_insn ("bgeu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           955:       break;
        !           956:     case GTU:
        !           957:       if (cc_status.flags & CC_IN_FCCR)
        !           958:        abort ();
        !           959:       else
        !           960:        output_asm_insn ("bgu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           961:       break;
        !           962:     case LEU:
        !           963:       if (cc_status.flags & CC_IN_FCCR)
        !           964:        abort ();
        !           965:       else
        !           966:        output_asm_insn ("bleu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           967:       break;
        !           968:     case LTU:
        !           969:       if (cc_status.flags & CC_IN_FCCR)
        !           970:        abort ();
        !           971:       else
        !           972:        output_asm_insn ("blu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
        !           973:       break;
        !           974:     default:
        !           975:       abort ();
        !           976:     }
        !           977:   return "";
        !           978: }
        !           979: 
        !           980: /* ??? Comment needed here */
        !           981: 
        !           982: char *
        !           983: output_delay_insn (template, operands, insn)
        !           984:      char *template;
        !           985:      rtx *operands;
        !           986:      rtx insn;
        !           987: {
        !           988:   extern char *insn_template[];
        !           989:   extern char *(*insn_outfun[])();
        !           990:   rtx pat = gen_rtx (SET, VOIDmode,
        !           991:                     XVECEXP (PATTERN (insn), 0, 0),
        !           992:                     XVECEXP (PATTERN (insn), 0, 1));
        !           993:   rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
        !           994:   int insn_code_number;
        !           995: 
        !           996:   /* Output the branch instruction first.  */
        !           997:   output_asm_insn (template, operands);
        !           998: 
        !           999:   /* Now recognize the insn which we put in its delay slot.
        !          1000:      We must do this after outputing the branch insn,
        !          1001:      since operands may just be a pointer to `recog_operands'.  */
        !          1002:   insn_code_number = recog (pat, delay_insn);
        !          1003:   if (insn_code_number == -1)
        !          1004:     abort ();
        !          1005: 
        !          1006:   /* Now get the template for what this insn would
        !          1007:      have been, without the branch.  Its operands are
        !          1008:      exactly the same as they would be, so we don't
        !          1009:      need to do an insn_extract.  */
        !          1010:   template = insn_template[insn_code_number];
        !          1011:   if (template == 0)
        !          1012:     template = (*insn_outfun[insn_code_number]) (operands, delay_insn);
        !          1013:   output_asm_insn (template, operands);
        !          1014:   return "";
        !          1015: }

unix.superglobalmegacorp.com

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