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

1.1       root        1: /* Subroutines for insn-output.c for Sun SPARC.
                      2:    Copyright (C) 1987 Free Software Foundation, Inc.
                      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
                     25:    the stack instead of the frame.  */
                     26: extern int frame_pointer_needed;
                     27: 
                     28: static rtx find_addr_reg ();
                     29: 
                     30: #if 0
                     31: /* RTL expressions that we will cache during the entire compilation.  */
                     32: rtx reg_o0_rtx, reg_o1_rtx, reg_o2_rtx, reg_i7_rtx;
                     33: 
                     34: void
                     35: init_emit_mdep ()
                     36: {
                     37:   /* These may be freely shared.  */
                     38:   reg_o0_rtx = gen_rtx (REG, SImode, 8);
                     39:   reg_o1_rtx = gen_rtx (REG, SImode, 9);
                     40:   reg_o2_rtx = gen_rtx (REG, SImode, 10);
                     41:   reg_i7_rtx = gen_rtx (REG, SImode, 31);
                     42: }
                     43: #endif
                     44: 
                     45: int
                     46: arith_operand (op, mode)
                     47:      rtx op;
                     48:      enum machine_mode mode;
                     49: {
                     50:   return (register_operand (op, mode)
                     51:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
                     52: }
                     53: 
                     54: int
                     55: arith32_operand (op, mode)
                     56:      rtx op;
                     57:      enum machine_mode mode;
                     58: {
                     59:   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
                     60: }
                     61: 
1.1.1.3 ! root       62: int
        !            63: small_int (op, mode)
        !            64:      rtx op;
        !            65:      enum machine_mode mode;
        !            66: {
        !            67:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
        !            68: }
        !            69: 
1.1       root       70: /* Return the best assembler insn template
                     71:    for moving operands[1] into operands[0] as a fullword.  */
                     72: 
                     73: static char *
                     74: singlemove_string (operands)
                     75:      rtx *operands;
                     76: {
                     77:   if (GET_CODE (operands[0]) == MEM)
                     78:     return "st %r1,%0";
                     79:   if (GET_CODE (operands[1]) == MEM)
                     80:     return "ld %1,%0";
1.1.1.3 ! root       81:   return "mov %1,%0";
1.1       root       82: }
                     83: 
                     84: /* Output assembler code to perform a doubleword move insn
                     85:    with operands OPERANDS.  */
                     86: 
                     87: char *
                     88: output_move_double (operands)
                     89:      rtx *operands;
                     90: {
                     91:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                     92:   rtx latehalf[2];
                     93:   rtx addreg0 = 0, addreg1 = 0;
                     94: 
                     95:   /* First classify both operands.  */
                     96: 
                     97:   if (REG_P (operands[0]))
                     98:     optype0 = REGOP;
                     99:   else if (offsetable_memref_p (operands[0]))
                    100:     optype0 = OFFSOP;
                    101:   else if (GET_CODE (operands[0]) == MEM)
                    102:     optype0 = MEMOP;
                    103:   else
                    104:     optype0 = RNDOP;
                    105: 
                    106:   if (REG_P (operands[1]))
                    107:     optype1 = REGOP;
                    108:   else if (CONSTANT_P (operands[1])
                    109:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    110:     optype1 = CNSTOP;
                    111:   else if (offsetable_memref_p (operands[1]))
                    112:     optype1 = OFFSOP;
                    113:   else if (GET_CODE (operands[1]) == MEM)
                    114:     optype0 = MEMOP;
                    115:   else
                    116:     optype1 = RNDOP;
                    117: 
                    118:   /* Check for the cases that the operand constraints are not
                    119:      supposed to allow to happen.  Abort if we get one,
                    120:      because generating code for these cases is painful.  */
                    121: 
                    122:   if (optype0 == RNDOP || optype1 == RNDOP)
                    123:     abort ();
                    124: 
                    125:   /* If an operand is an unoffsettable memory ref, find a register
                    126:      we can increment temporarily to make it refer to the second word.  */
                    127: 
                    128:   if (optype0 == MEMOP)
                    129:     addreg0 = find_addr_reg (operands[0]);
                    130: 
                    131:   if (optype1 == MEMOP)
                    132:     addreg1 = find_addr_reg (operands[1]);
                    133: 
                    134:   /* Ok, we can do one word at a time.
                    135:      Normally we do the low-numbered word first,
                    136:      but if either operand is autodecrementing then we
                    137:      do the high-numbered word first.
                    138: 
                    139:      In either case, set up in LATEHALF the operands to use
                    140:      for the high-numbered word and in some cases alter the
                    141:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    142: 
                    143:   if (optype0 == REGOP)
                    144:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    145:   else if (optype0 == OFFSOP)
                    146:     latehalf[0] = adj_offsetable_operand (operands[0], 4);
                    147:   else
                    148:     latehalf[0] = operands[0];
                    149: 
                    150:   if (optype1 == REGOP)
                    151:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    152:   else if (optype1 == OFFSOP)
                    153:     latehalf[1] = adj_offsetable_operand (operands[1], 4);
                    154:   else if (optype1 == CNSTOP)
                    155:     {
                    156:       if (CONSTANT_P (operands[1]))
                    157:        latehalf[1] = const0_rtx;
                    158:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    159:        {
                    160:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
                    161:          operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
                    162:        }
                    163:     }
                    164:   else
                    165:     latehalf[1] = operands[1];
                    166: 
                    167:   /* If the first move would clobber the source of the second one,
1.1.1.3 ! root      168:      do them in the other order.
        !           169: 
        !           170:      RMS says "This happens only for registers;
1.1       root      171:      such overlap can't happen in memory unless the user explicitly
1.1.1.3 ! root      172:      sets it up, and that is an undefined circumstance."
        !           173: 
        !           174:      but it happens on the sparc when loading parameter registers,
        !           175:      so I am going to define that circumstance, and make it work
        !           176:      as expected.  */
        !           177: 
        !           178:   /* Easy case: try moving both words at once.  */
        !           179:   if ((optype0 == REGOP && optype1 != REGOP
        !           180:        && (REGNO (operands[0]) & 1) == 0)
        !           181:       || (optype0 != REGOP && optype1 == REGOP
        !           182:          && (REGNO (operands[1]) & 1) == 0))
        !           183:     {
        !           184:       rtx op1, op2;
        !           185:       rtx base = 0, offset = const0_rtx;
1.1       root      186: 
1.1.1.3 ! root      187:       if (optype0 == REGOP)
        !           188:        op1 = operands[0], op2 = XEXP (operands[1], 0);
        !           189:       else
        !           190:        op1 = operands[1], op2 = XEXP (operands[0], 0);
        !           191: 
        !           192:       /* We know structs are properly aligned.  */
        !           193:       if (operands[1]->in_struct)
        !           194:        return "ldd %1,%0";
        !           195:       if (operands[0]->in_struct)
        !           196:        return "std %1,%0";
        !           197: 
        !           198:       /* Otherwise, only trust global variables
        !           199:         and even offsets from the frame pointer.  */
        !           200:       if (GET_CODE (op2) == SYMBOL_REF
        !           201:          || GET_CODE (op2) == CONST
        !           202:          || GET_CODE (op2) == REG)
        !           203:        base = op2;
        !           204:       else if (GET_CODE (op2) == PLUS)
        !           205:        if (GET_CODE (XEXP (op2, 0)) == REG)
        !           206:          base = XEXP (op2, 0),
        !           207:          offset = XEXP (op2, 1);
        !           208:        else if (GET_CODE (XEXP (op2, 1)) == REG)
        !           209:          base = XEXP (op2, 1),
        !           210:          offset = XEXP (op2, 0);
        !           211: 
        !           212:       if (base
        !           213:          && (GET_CODE (base) != REG
        !           214:              || (REGNO (base) == FRAME_POINTER_REGNUM
        !           215:                  && GET_CODE (offset) == CONST_INT
        !           216:                  && INTVAL (offset) & 0x7 == 0)))
        !           217:        if (op1 == operands[0])
        !           218:          return "ldd %1,%0";
        !           219:        else
        !           220:          return "std %1,%0";
        !           221:     }
        !           222:       
1.1       root      223:   if (optype0 == REGOP && optype1 == REGOP
                    224:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    225:     {
                    226:       /* Make any unoffsetable addresses point at high-numbered word.  */
                    227:       if (addreg0)
                    228:        output_asm_insn ("add %0,0x4,%0", &addreg0);
                    229:       if (addreg1)
                    230:        output_asm_insn ("add %0,0x4,%0", &addreg1);
                    231: 
                    232:       /* Do that word.  */
                    233:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    234: 
                    235:       /* Undo the adds we just did.  */
                    236:       if (addreg0)
                    237:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    238:       if (addreg1)
                    239:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    240: 
                    241:       /* Do low-numbered word.  */
                    242:       return singlemove_string (operands);
                    243:     }
1.1.1.3 ! root      244:   else if (optype0 == REGOP && optype1 != REGOP
        !           245:           && reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
        !           246:     {
        !           247:       /* Do the late half first.  */
        !           248:       output_asm_insn (singlemove_string (latehalf), latehalf);
        !           249:       /* Then clobber.  */
        !           250:       return singlemove_string (operands);
        !           251:     }
1.1       root      252: 
                    253:   /* Normal case: do the two words, low-numbered first.  */
                    254: 
                    255:   output_asm_insn (singlemove_string (operands), operands);
                    256: 
                    257:   /* Make any unoffsetable addresses point at high-numbered word.  */
                    258:   if (addreg0)
                    259:     output_asm_insn ("add %0,0x4,%0", &addreg0);
                    260:   if (addreg1)
                    261:     output_asm_insn ("add %0,0x4,%0", &addreg1);
                    262: 
                    263:   /* Do that word.  */
                    264:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    265: 
                    266:   /* Undo the adds we just did.  */
                    267:   if (addreg0)
                    268:     output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    269:   if (addreg1)
                    270:     output_asm_insn ("add %0,-0x4,%0", &addreg1);
                    271: 
                    272:   return "";
                    273: }
                    274: 
                    275: static char *
                    276: output_fp_move_double (operands)
                    277:      rtx *operands;
                    278: {
                    279:   if (FP_REG_P (operands[0]))
                    280:     {
                    281:       if (FP_REG_P (operands[1]))
                    282:        {
                    283:          output_asm_insn ("fmovs %1,%0", operands);
                    284:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    285:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    286:          return "fmovs %1,%0";
                    287:        }
                    288:       if (GET_CODE (operands[1]) == REG)
                    289:        {
1.1.1.3 ! root      290:          if ((REGNO (operands[1]) & 1) == 0)
        !           291:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
        !           292:          else
        !           293:            {
        !           294:              rtx xoperands[3];
        !           295:              xoperands[0] = operands[0];
        !           296:              xoperands[1] = operands[1];
        !           297:              xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
        !           298:              output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands);
        !           299:              return "";
        !           300:            }
1.1       root      301:        }
                    302:       return "ldd %1,%0";
                    303:     }
                    304:   else if (FP_REG_P (operands[1]))
                    305:     {
                    306:       if (GET_CODE (operands[0]) == REG)
                    307:        {
1.1.1.3 ! root      308:          if ((REGNO (operands[0]) & 1) == 0)
        !           309:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
        !           310:          else
        !           311:            {
        !           312:              rtx xoperands[3];
        !           313:              xoperands[2] = operands[1];
        !           314:              xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
        !           315:              xoperands[0] = operands[0];
        !           316:              output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);
        !           317:              return "";
        !           318:            }
1.1       root      319:        }
                    320:       return "std %1,%0";
                    321:     }
1.1.1.3 ! root      322:   else abort ();
1.1       root      323: }
                    324: 
                    325: /* Return a REG that occurs in ADDR with coefficient 1.
                    326:    ADDR can be effectively incremented by incrementing REG.  */
                    327: 
                    328: static rtx
                    329: find_addr_reg (addr)
                    330:      rtx addr;
                    331: {
                    332:   while (GET_CODE (addr) == PLUS)
                    333:     {
                    334:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    335:        addr = XEXP (addr, 0);
                    336:       if (GET_CODE (XEXP (addr, 1)) == REG)
                    337:        addr = XEXP (addr, 1);
                    338:       if (CONSTANT_P (XEXP (addr, 0)))
                    339:        addr = XEXP (addr, 1);
                    340:       if (CONSTANT_P (XEXP (addr, 1)))
                    341:        addr = XEXP (addr, 0);
                    342:     }
                    343:   if (GET_CODE (addr) == REG)
                    344:     return addr;
                    345:   return 0;
                    346: }
                    347: 
                    348: /* Load the address specified by OPERANDS[3] into the register
                    349:    specified by OPERANDS[0].
                    350: 
                    351:    OPERANDS[3] may be the result of a sum, hence it could either be:
                    352: 
                    353:    (1) CONST
                    354:    (2) REG
                    355:    (2) REG + CONST_INT
                    356:    (3) REG + REG + CONST_INT
                    357: 
                    358:    All cases are handled here.  */
                    359: 
                    360: void
                    361: output_load_address (operands)
                    362:      rtx *operands;
                    363: {
                    364:   rtx base, offset;
                    365: 
                    366:   if (CONSTANT_P (operands[3]))
                    367:     {
                    368:       output_asm_insn ("set %3,%0", operands);
                    369:       return;
                    370:     }
                    371: 
                    372:   if (REG_P (operands[3]))
                    373:     {
                    374:       if (REGNO (operands[0]) != REGNO (operands[3]))
                    375:        output_asm_insn ("mov %3,%0", operands);
                    376:       return;
                    377:     }
                    378: 
                    379:   base = XEXP (operands[3], 0);
                    380:   offset = XEXP (operands[3], 1);
                    381: 
                    382:   if (GET_CODE (base) == CONST_INT)
                    383:     {
                    384:       rtx tmp = base;
                    385:       base = offset;
                    386:       offset = tmp;
                    387:     }
                    388: 
                    389:   if (GET_CODE (offset) != CONST_INT)
                    390:     abort ();
                    391: 
                    392:   if (REG_P (base))
                    393:     {
                    394:       operands[6] = base;
                    395:       operands[7] = offset;
                    396:       if (SMALL_INT (offset))
                    397:        output_asm_insn ("add %6,%7,%0", operands);
                    398:       else
                    399:        output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
                    400:     }
                    401:   else
                    402:     {
                    403:       operands[6] = XEXP (base, 0);
                    404:       operands[7] = XEXP (base, 1);
                    405:       operands[8] = offset;
                    406: 
                    407:       if (SMALL_INT (offset))
                    408:        output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
                    409:       else
                    410:        output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
                    411:     }
                    412: }
                    413: 
                    414: char *
                    415: output_block_move (operands)
                    416:      rtx *operands;
                    417: {
                    418:   static int movstrsi_label = 0;
                    419:   int align = 4;
                    420: 
                    421:   rtx xoperands[9];
                    422:   int available[3];
                    423:   int i, j;
                    424: 
                    425:   /* Since we clobber untold things, nix the condition codes.  */
                    426:   CC_STATUS_INIT;
                    427: 
                    428:   /* Get past the MEMs.  */
                    429:   operands[0] = XEXP (operands[0], 0);
                    430:   operands[1] = XEXP (operands[1], 0);
                    431: 
                    432:   xoperands[0] = 0;
                    433:   xoperands[1] = 0;
                    434:   xoperands[2] = 0;
                    435: 
                    436:   available[0] = 1;
                    437:   available[1] = 1;
                    438:   available[2] = 1;
                    439: #if 1
                    440:   /* Prepare to juggle registers if necessary.  */
                    441:   if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 8) < 3)
                    442:     {
                    443:       xoperands[0] = operands[0];
                    444:       available[REGNO (operands[0]) - 8] = 0;
                    445:     }
                    446:   if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 8) < 3)
                    447:     {
                    448:       xoperands[1] = operands[1];
                    449:       available[REGNO (operands[1]) - 8] = 0;
                    450:     }
                    451:   if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 8) < 3)
                    452:     {
                    453:       xoperands[2] = operands[2];
                    454:       available[REGNO (operands[2]) - 8] = 0;
                    455:     }
                    456:   for (i = 0; i < 3; i++)
                    457:     {
                    458:       if (xoperands[i])
                    459:        continue;
                    460:       if (available[0])
                    461:        {
                    462:          xoperands[i] = gen_rtx (REG, SImode, 8);
                    463:          available[0] = 0;
                    464:          continue;
                    465:        }
                    466:       if (available[1])
                    467:        {
                    468:          xoperands[i] = gen_rtx (REG, SImode, 9);
                    469:          available[1] = 0;
                    470:          continue;
                    471:        }
                    472:       xoperands[i] = gen_rtx (REG, SImode, 10);
                    473:       available[2] = 0;
                    474:     }
                    475: #endif
                    476: 
                    477:   /* First, figure out best alignment we may assume.  */
                    478:   if (REG_P (operands[2]))
                    479:     {
                    480:       xoperands[5] = operands[2];
                    481:       output_asm_insn ("sub %5,0x1,%2", xoperands);
                    482:       align = 1;
                    483:     }
                    484:   else
                    485:     {
                    486:       int i = INTVAL (operands[2]);
                    487: 
                    488:       if (i & 1)
                    489:        align = 1;
                    490:       else if (i & 3)
                    491:        align = 2;
                    492: 
                    493:       /* predecrement count.  */
                    494:       i -= align;
                    495:       if (i < 0) abort ();
                    496: 
                    497:       xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i);
                    498: 
                    499:       output_asm_insn ("set %5,%2", xoperands);
                    500:     }
                    501: 
                    502:   /* Now, set up for pipelined operation: dest must contain
                    503:      a pre-incremented address, because its index is pre-decremented.  */
                    504: 
                    505:   xoperands[3] = plus_constant (operands[0], align);
                    506:   output_load_address (xoperands);
                    507: 
                    508:   xoperands[4] = operands[1];
                    509:   output_load_address (xoperands+1);
                    510: 
                    511:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                    512:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
                    513: 
                    514:   output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%o7\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%o7,[%0+%2]", xoperands);
                    515:   return "";
                    516: }
                    517: 
                    518: #define ABS(x) ((x) < 0 ? -(x) : x)
                    519: 
                    520: char *
                    521: output_mul_by_constant (insn, operands, unsignedp)
                    522:      rtx insn;
                    523:      rtx *operands;
                    524:      int unsignedp;
                    525: {
                    526:   int c;                       /* Size of constant */
                    527:   int shifts[BITS_PER_WORD];   /* Table of shifts */
                    528:   int p, log;                  /* A power of two, and its log */
                    529:   int d1, d2;                  /* Differences of c and p */
                    530:   int first = 1;               /* True if dst has unknown data in it */
                    531:   int i;
                    532: 
                    533:   c = INTVAL (operands[2]);
                    534:   if (c == 0)
                    535:     {
                    536:       /* should not happen.  */
                    537:       abort ();
                    538:       if (GET_CODE (operands[0]) == MEM)
                    539:        return "st %%g0,%0";
                    540:       return "mov %%g0,%0";
                    541:     }
                    542: 
                    543: #if 0
                    544:   printf ("open coding insn:\n");
                    545:   debug_rtx (insn);
                    546:   printf ("done.\n");
                    547: #endif
                    548: 
                    549:   output_asm_insn ("! start open coded multiply");
                    550: 
                    551:   /* Clear out the table of shifts. */
                    552:   for (i = 0; i < BITS_PER_WORD; ++i)
                    553:     shifts[i] = 0;
                    554: 
                    555:   while (c)
                    556:     {
                    557:       /* Find the power of two nearest ABS(c) */
                    558:       p = 1, log = 0;
                    559:       do
                    560:        {
                    561:          d1 = ABS(c) - p;
                    562:          p *= 2;
                    563:          ++log;
                    564:        }
                    565:       while (p < ABS(c));
                    566:       d2 = p - ABS(c);
                    567: 
                    568:       /* Make an appropriate entry in shifts for p. */
                    569:       if (d2 < d1)
                    570:        {
                    571:          shifts[log] = c < 0 ? -1 : 1;
                    572:          c = c < 0 ? d2 : -d2;
                    573:        }
                    574:       else
                    575:        {
                    576:          shifts[log - 1] = c < 0 ? -1 : 1;
                    577:          c = c < 0 ? -d1 : d1;
                    578:        }
                    579:     }
                    580: 
                    581:   /* For now, use a known clobberable register.  This could
                    582:      be improved by looking at insn, and seeing if we
                    583:      have a dying register contained therein.  */
                    584:   regs_ever_live[15] = 1;
                    585:   operands[3] = gen_rtx (REG, SImode, 15);
                    586: 
                    587:   /* Take care of the first insn in sequence.
                    588:      We know we have at least one. */
                    589: 
                    590:   /* A value of -1 in shifts says to subtract that power of two, and a value
                    591:      of 1 says to add that power of two. */
                    592:   for (i = 0; ; i++)
                    593:     if (shifts[i])
                    594:       {
                    595:        if (i)
                    596:          {
                    597:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i);
                    598:            output_asm_insn ("sll %1,%2,%3", operands);
                    599:          }
                    600:        else if (REGNO (operands[3]) == 15)
                    601:          output_asm_insn ("mov %1,%3", operands);
                    602: 
                    603:        log = i;
                    604:        if (shifts[i] < 0)
                    605:          output_asm_insn ("sub %%g0,%3,%0", operands);
                    606:        else
                    607:          output_asm_insn ("mov %3,%0", operands);
                    608:        break;
                    609:       }
                    610: 
                    611:   /* A value of -1 in shifts says to subtract that power of two, and a value
                    612:      of 1 says to add that power of two--continued.  */
                    613:   for (i += 1; i < BITS_PER_WORD; ++i)
                    614:     if (shifts[i])
                    615:       {
                    616:        if (i - log > 0)
                    617:          {
                    618:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log);
                    619:            output_asm_insn ("sll %3,%2,%3", operands);
                    620:          }
                    621:        else
                    622:          {
                    623:            operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i);
                    624:            output_asm_insn ("sra %3,%2,%3", operands);
                    625:          }
                    626:        log = i;
                    627:        if (shifts[i] < 0)
                    628:          output_asm_insn ("sub %0,%3,%0", operands);
                    629:        else
                    630:          output_asm_insn ("add %0,%3,%0", operands);
                    631:       }
                    632: 
                    633:   output_asm_insn ("! end open coded multiply");
                    634: 
                    635:   return "";
                    636: }
                    637: 
                    638: char *
                    639: output_mul_insn (operands, unsignedp)
                    640:      rtx *operands;
                    641:      int unsignedp;
                    642: {
                    643:   int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1;
                    644:   int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1;
                    645: 
                    646:   if (lucky1)
                    647:     if (lucky2)
                    648:       output_asm_insn ("call .mul,2\n\tnop", operands);
                    649:     else
                    650:       {
                    651:        rtx xoperands[2];
                    652:        xoperands[0] = gen_rtx (REG, SImode,
                    653:                                8 ^ (REGNO (operands[1]) == 8));
                    654:        xoperands[1] = operands[2];
                    655:        output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                    656:       }
                    657:   else if (lucky2)
                    658:     {
                    659:       rtx xoperands[2];
                    660:       xoperands[0] = gen_rtx (REG, SImode,
                    661:                              8 ^ (REGNO (operands[2]) == 8));
                    662:       xoperands[1] = operands[1];
                    663:       output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                    664:     }
                    665:   else
                    666:     {
                    667:       output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1",
                    668:                       operands);
                    669:     }
                    670: 
                    671:   if (REGNO (operands[0]) == 8)
                    672:     return "";
                    673:   return "mov %%o0,%0";
                    674: }
                    675: 
                    676: #if 0
                    677: /* This function does not properly protect its operands.  */
                    678: char *
                    679: output_arith_insn (operands, name)
                    680:      rtx *operands;
                    681:      char *name;
                    682: {
                    683:   extern struct _iobuf *asm_out_file;
                    684: 
                    685:   /* Does not commute.  */
                    686:   rtx op1 = 0;
                    687:   rtx op2 = 0;
                    688: 
                    689:   abort ();
                    690:   if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 8)
                    691:     op1 = operands[1];
                    692:   if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 8)
                    693:     op2 = operands[2];
                    694: 
                    695:   if (op1 && op2)
                    696:     {
                    697:       /* ?? should have been done earlier.  */
                    698:       abort ();
                    699:     }
                    700:   else
                    701:     {
                    702:       if (op2)
                    703:        {
                    704:          op1 = operands[1];
                    705:          if (REG_P (op1) && REGNO (op1) == 9)
                    706:            {
                    707:              output_asm_insn ("mov %%o1,%%o2\n\tmov %%o0,%%o1", operands);
                    708:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    709:              output_asm_insn ("mov %%o2,%%o0", operands);
                    710:              goto done;
                    711:            }
                    712:          output_asm_insn ("mov %%o0,%%o1", operands);
                    713:          if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1))
                    714:            {
                    715:              output_asm_insn ("sethi %%hi(%1),%%o0", operands);
                    716:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    717:              output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands);
                    718:            }
                    719:          else
                    720:            {
                    721:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    722:              if (GET_CODE (op1) == MEM)
                    723:                output_asm_insn ("ld %1,%%o0", operands);
                    724:              else
                    725:                output_asm_insn ("mov %1,%%o0", operands);
                    726:            }
                    727:        }
                    728:       else if (op1)
                    729:        {
                    730:          op2 = operands[2];
                    731:          if (REG_P (op2) && REGNO (operands[1]) == 9)
                    732:            {
                    733:              fprintf (asm_out_file, "\tcall %s,2\n\tnop\n");
                    734:              goto done;
                    735:            }
                    736:          if (GET_CODE (op2) == CONST_INT && ! SMALL_INT (op2))
                    737:            {
                    738:              output_asm_insn ("sethi %%hi(%2),%%o1", operands);
                    739:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    740:              output_asm_insn ("add %%o1,%%lo(%2),%%o1", operands);
                    741:            }
                    742:          else
                    743:            {
                    744:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    745:              if (GET_CODE (op2) == MEM)
                    746:                output_asm_insn ("ld %2,%%o1", operands);
                    747:              else
                    748:                output_asm_insn ("mov %2,%%o1", operands);
                    749:            }
                    750:        }
                    751:       else
                    752:        {
                    753:          op1 = operands[1];
                    754:          op2 = operands[2];
                    755: 
                    756:          if (! REG_P (op2) || REGNO (op2) != 9)
                    757:            if (GET_CODE (op2) == MEM)
                    758:              output_asm_insn ("ld %2,%%o1", operands);
                    759:            else if (GET_CODE (op2) != CONST_INT || SMALL_INT (op2))
                    760:              output_asm_insn ("mov %2,%%o1", operands);
                    761:            else
                    762:              output_asm_insn ("sethi %%hi(%2),%%o1\n\tadd %%o1,%%lo(%2),%%o1", operands);
                    763:          if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1))
                    764:            {
                    765:              output_asm_insn ("sethi %%hi(%1),%%o0", operands);
                    766:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    767:              output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands);
                    768:            }
                    769:          else
                    770:            {
                    771:              fprintf (asm_out_file, "\tcall %s,2\n", name);
                    772:              if (GET_CODE (op1) == MEM)
                    773:                output_asm_insn ("ld %1,%%o0", operands);
                    774:              else
                    775:                output_asm_insn ("mov %1,%%o0", operands);
                    776:            }
                    777:        }
                    778:     done:
                    779:       if (REG_P (operands[0]) && REGNO (operands[0]) == 8)
                    780:        return "";
                    781:       if (GET_CODE (operands[0]) == MEM)
                    782:        return "st %%o0,%0";
                    783:       return "mov %%o0,%0";
                    784:     }
                    785: }
                    786: #endif
                    787: 
                    788: /* Make floating point register f0 contain 0.
                    789:    SIZE is the number of registers (including f0)
                    790:    which should contain 0.  */
                    791: 
                    792: void
                    793: make_f0_contain_0 (size)
                    794:      int size;
                    795: {
                    796:   if (size == 1)
1.1.1.3 ! root      797:     output_asm_insn ("ld [%%fp-16],%%f0", 0);
1.1       root      798:   else if (size == 2)
1.1.1.3 ! root      799:     output_asm_insn ("ldd [%%fp-16],%%f0", 0);
1.1       root      800: }

unix.superglobalmegacorp.com

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