Annotation of gcc/config/out-i860.c, revision 1.1.1.2

1.1       root        1: /* Subroutines for insn-output.c for Intel 860
                      2:    Copyright (C) 1989 Free Software Foundation, Inc.
                      3:    Derived from out-sparc.c.
                      4: 
                      5: This file is part of GNU CC.
                      6: 
                      7: GNU CC is free software; you can redistribute it and/or modify
                      8: it under the terms of the GNU General Public License as published by
                      9: the Free Software Foundation; either version 1, or (at your option)
                     10: any later version.
                     11: 
                     12: GNU CC is distributed in the hope that it will be useful,
                     13: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     15: GNU General Public License for more details.
                     16: 
                     17: You should have received a copy of the GNU General Public License
                     18: along with GNU CC; see the file COPYING.  If not, write to
                     19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     20: 
                     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, and if we learn how
                     26:    to renumber all the registers when we don't do a save (hard!).  */
                     27: extern int frame_pointer_needed;
                     28: 
                     29: static rtx find_addr_reg ();
                     30: 
                     31: /* Return non-zero only if OP is a register of mode MODE,
                     32:    or const0_rtx.  */
                     33: int
                     34: reg_or_0_operand (op, mode)
                     35:      rtx op;
                     36:      enum machine_mode mode;
                     37: {
                     38:   return (op == const0_rtx || register_operand (op, mode)
                     39:          || op == CONST0_RTX (mode));
                     40: }
                     41: 
                     42: /* Return non-zero if this pattern, can be evaluated safely, even if it
                     43:    was not asked for.  */
                     44: int
                     45: safe_insn_src_p (op, mode)
                     46:      rtx op;
                     47:      enum machine_mode mode;
                     48: {
                     49:   /* Just experimenting.  */
                     50: 
                     51:   /* No floating point src is safe if it contains an arithmetic
                     52:      operation, since that operation may trap.  */
                     53:   switch (GET_CODE (op))
                     54:     {
                     55:     case CONST_INT:
                     56:     case LABEL_REF:
                     57:     case SYMBOL_REF:
                     58:     case CONST:
                     59:       return 1;
                     60: 
                     61:     case REG:
                     62:       return 1;
                     63: 
                     64:     case MEM:
                     65:       return CONSTANT_ADDRESS_P (XEXP (op, 0));
                     66: 
                     67:       /* We never need to negate or complement constants.  */
                     68:     case NEG:
                     69:       return (mode != SFmode && mode != DFmode);
                     70:     case NOT:
                     71:     case ZERO_EXTEND:
                     72:       return 1;
                     73: 
                     74:     case EQ:
                     75:     case NE:
                     76:     case LT:
                     77:     case GT:
                     78:     case LE:
                     79:     case GE:
                     80:     case LTU:
                     81:     case GTU:
                     82:     case LEU:
                     83:     case GEU:
                     84:     case MINUS:
                     85:     case PLUS:
                     86:       return (mode != SFmode && mode != DFmode);
                     87:     case AND:
                     88:     case IOR:
                     89:     case XOR:
                     90:     case LSHIFT:
                     91:     case ASHIFT:
                     92:     case ASHIFTRT:
                     93:     case LSHIFTRT:
                     94:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
                     95:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
                     96:        return 0;
                     97:       return 1;
                     98: 
                     99:     default:
                    100:       return 0;
                    101:     }
                    102: }
                    103: 
                    104: /* Return 1 if REG is clobbered in IN.
                    105:    Return 2 if REG is used in IN. 
                    106:    Return 3 if REG is both used and clobbered in IN.
                    107:    Return 0 if neither.  */
                    108: 
                    109: static int
                    110: reg_clobbered_p (reg, in)
                    111:      rtx reg;
                    112:      rtx in;
                    113: {
                    114:   register enum rtx_code code;
                    115: 
                    116:   if (in == 0)
                    117:     return 0;
                    118: 
                    119:   code = GET_CODE (in);
                    120: 
                    121:   if (code == SET || code == CLOBBER)
                    122:     {
                    123:       rtx dest = SET_DEST (in);
                    124:       int set = 0;
                    125:       int used = 0;
                    126: 
                    127:       while (GET_CODE (dest) == STRICT_LOW_PART
                    128:             || GET_CODE (dest) == SUBREG
                    129:             || GET_CODE (dest) == SIGN_EXTRACT
                    130:             || GET_CODE (dest) == ZERO_EXTRACT)
                    131:        dest = XEXP (dest, 0);
                    132: 
                    133:       if (dest == reg)
                    134:        set = 1;
                    135:       else if (GET_CODE (dest) == REG
                    136:               && refers_to_regno_p (REGNO (reg),
                    137:                                     REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
                    138:                                     SET_DEST (in), 0))
                    139:        {
                    140:          set = 1;
                    141:          /* Anything that sets just part of the register
                    142:             is considered using as well as setting it.
                    143:             But note that a straight SUBREG of a single-word value
                    144:             clobbers the entire value.   */
                    145:          if (dest != SET_DEST (in)
                    146:              && ! (GET_CODE (SET_DEST (in)) == SUBREG
                    147:                    || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))
                    148:            used = 1;
                    149:        }
                    150: 
                    151:       if (code == SET)
                    152:        {
                    153:          if (set)
                    154:            used = refers_to_regno_p (REGNO (reg),
                    155:                                      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
                    156:                                      SET_SRC (in), 0);
                    157:          else
                    158:            used = refers_to_regno_p (REGNO (reg),
                    159:                                      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
                    160:                                      in, 0);
                    161:        }
                    162: 
                    163:       return set + used * 2;
                    164:     }
                    165: 
                    166:   if (refers_to_regno_p (REGNO (reg),
                    167:                         REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
                    168:                         in, 0))
                    169:     return 2;
                    170:   return 0;
                    171: }
                    172: 
                    173: /* Return non-zero if OP can be written to without screwing up
                    174:    GCC's model of what's going on.  It is assumed that this operand
                    175:    appears in the dest position of a SET insn in a conditional
                    176:    branch's delay slot.  AFTER is the label to start looking from.  */
                    177: int
                    178: operand_clobbered_before_used_after (op, after)
                    179:      rtx op;
                    180:      rtx after;
                    181: {
                    182:   extern char call_used_regs[];
                    183: 
                    184:   /* Just experimenting.  */
                    185:   if (GET_CODE (op) == CC0)
                    186:     return 1;
                    187:   if (GET_CODE (op) == REG)
                    188:     {
                    189:       rtx insn;
                    190: 
                    191:       if (op == stack_pointer_rtx)
                    192:        return 0;
                    193: 
                    194:       /* Scan forward from the label, to see if the value of OP
                    195:         is clobbered before the first use.  */
                    196: 
                    197:       for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
                    198:        {
                    199:          if (GET_CODE (insn) == NOTE)
                    200:            continue;
                    201:          if (GET_CODE (insn) == INSN
                    202:              || GET_CODE (insn) == JUMP_INSN
                    203:              || GET_CODE (insn) == CALL_INSN)
                    204:            {
                    205:              switch (reg_clobbered_p (op, PATTERN (insn)))
                    206:                {
                    207:                default:
                    208:                  return 0;
                    209:                case 1:
                    210:                  return 1;
                    211:                case 0:
                    212:                  break;
                    213:                }
                    214:            }
                    215:          /* If we reach another label without clobbering OP,
                    216:             then we cannot safely write it here.  */
                    217:          else if (GET_CODE (insn) == CODE_LABEL)
                    218:            return 0;
                    219:          if (GET_CODE (insn) == JUMP_INSN)
                    220:            {
                    221:              if (condjump_p (insn))
                    222:                return 0;
                    223:              /* This is a jump insn which has already
                    224:                 been mangled.  We can't tell what it does.  */
                    225:              if (GET_CODE (PATTERN (insn)) == PARALLEL)
                    226:                return 0;
                    227:              if (! JUMP_LABEL (insn))
                    228:                return 0;
                    229:              /* Keep following jumps.  */
                    230:              insn = JUMP_LABEL (insn);
                    231:            }
                    232:        }
                    233:       return 1;
                    234:     }
                    235: 
                    236:   /* In both of these cases, the first insn executed
                    237:      for this op will be a orh whatever%h,r0,r31,
                    238:      which is tolerable.  */
                    239:   if (GET_CODE (op) == MEM)
                    240:     return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
                    241: 
                    242:   return 0;
                    243: }
                    244: 
                    245: /* Return non-zero if this pattern, as a source to a "SET",
                    246:    is known to yield an instruction of unit size.  */
                    247: int
                    248: single_insn_src_p (op, mode)
                    249:      rtx op;
                    250:      enum machine_mode mode;
                    251: {
                    252:   switch (GET_CODE (op))
                    253:     {
                    254:     case CONST_INT:
                    255:       /* This is not always a single insn src, technically,
                    256:         but output_delayed_branch knows how to deal with it.  */
                    257:       return 1;
                    258: 
                    259:     case SYMBOL_REF:
                    260:     case CONST:
                    261:       /* This is not a single insn src, technically,
                    262:         but output_delayed_branch knows how to deal with it.  */
                    263:       return 1;
                    264: 
                    265:     case REG:
                    266:       return 1;
                    267: 
                    268:     case MEM:
                    269:       return 1;
                    270: 
                    271:       /* We never need to negate or complement constants.  */
                    272:     case NEG:
                    273:       return (mode != DFmode);
                    274:     case NOT:
                    275:     case ZERO_EXTEND:
                    276:       return 1;
                    277: 
                    278:     case EQ:
                    279:     case NE:
                    280:     case LT:
                    281:     case GT:
                    282:     case LE:
                    283:     case GE:
                    284:     case LTU:
                    285:     case GTU:
                    286:     case LEU:
                    287:     case GEU:
                    288:     case MINUS:
                    289:     case PLUS:
                    290:       /* Not doing floating point, since they probably
                    291:         take longer than the branch slot they might fill.  */
                    292:       return (mode != SFmode && mode != DFmode);
                    293:     case AND:
                    294:     case IOR:
                    295:     case XOR:
                    296:     case LSHIFT:
                    297:     case ASHIFT:
                    298:     case ASHIFTRT:
                    299:     case LSHIFTRT:
                    300:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
                    301:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
                    302:        return 0;
                    303:       return 1;
                    304: 
                    305:     case SUBREG:
                    306:       if (SUBREG_WORD (op) != 0)
                    307:        return 0;
                    308:       return single_insn_src_p (SUBREG_REG (op), mode);
                    309: 
                    310:       /* Not doing floating point, since they probably
                    311:         take longer than the branch slot they might fill.  */
                    312:     case FLOAT_EXTEND:
                    313:     case FLOAT_TRUNCATE:
                    314:     case FLOAT:
                    315:     case FIX:
                    316:     case UNSIGNED_FLOAT:
                    317:     case UNSIGNED_FIX:
                    318:       return 0;
                    319: 
                    320:     default:
                    321:       return 0;
                    322:     }
                    323: }
                    324: 
                    325: /* Nonzero only if this *really* is a single insn operand.  */
                    326: int
                    327: strict_single_insn_op_p (op, mode)
                    328:      rtx op;
                    329:      enum machine_mode mode;
                    330: {
                    331:   if (mode == VOIDmode)
                    332:     mode = GET_MODE (op);
                    333: 
                    334:   switch (GET_CODE (op))
                    335:     {
                    336:     case CC0:
                    337:       return 1;
                    338: 
                    339:     case CONST_INT:
                    340:       if (SMALL_INT (op))
                    341:        return 1;
                    342:       /* We can put this set insn into delay slot, because this is one
                    343:         insn; 'sethi'.  */
                    344:       if ((INTVAL (op) & 0x3ff) == 0)
                    345:        return 1;
                    346:       return 0;
                    347: 
                    348:     case SYMBOL_REF:
                    349:       return 0;
                    350: 
                    351:     case REG:
                    352: #if 0
                    353:       /* This loses when moving an freg to a general reg.  */
                    354:       return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
                    355: #endif
                    356:       return (mode != DFmode && mode != DImode);
                    357: 
                    358:     case MEM:
                    359:       if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
                    360:        return (mode != DFmode && mode != DImode);
                    361:       return 0;
                    362: 
                    363:       /* We never need to negate or complement constants.  */
                    364:     case NEG:
                    365:       return (mode != DFmode);
                    366:     case NOT:
                    367:     case ZERO_EXTEND:
                    368:       return 1;
                    369: 
                    370:     case EQ:
                    371:     case NE:
                    372:     case LT:
                    373:     case GT:
                    374:     case LE:
                    375:     case GE:
                    376:     case LTU:
                    377:     case GTU:
                    378:     case LEU:
                    379:     case GEU:
                    380:     case MINUS:
                    381:     case PLUS:
                    382:     case AND:
                    383:     case IOR:
                    384:     case XOR:
                    385:     case LSHIFT:
                    386:     case ASHIFT:
                    387:     case ASHIFTRT:
                    388:     case LSHIFTRT:
                    389:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
                    390:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
                    391:        return 0;
                    392:       return 1;
                    393: 
                    394:     case SUBREG:
                    395:       if (SUBREG_WORD (op) != 0)
                    396:        return 0;
                    397:       return strict_single_insn_op_p (SUBREG_REG (op), mode);
                    398: 
                    399:     case SIGN_EXTEND:
                    400:       if (GET_CODE (XEXP (op, 0)) == MEM
                    401:          && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
                    402:        return 1;
                    403:       return 0;
                    404: 
                    405:       /* Not doing floating point, since they probably
                    406:         take longer than the branch slot they might fill.  */
                    407:     case FLOAT_EXTEND:
                    408:     case FLOAT_TRUNCATE:
                    409:     case FLOAT:
                    410:     case FIX:
                    411:     case UNSIGNED_FLOAT:
                    412:     case UNSIGNED_FIX:
                    413:       return 0;
                    414: 
                    415:     default:
                    416:       return 0;
                    417:     }
                    418: }
                    419: 
                    420: /* Return truth value of whether OP is a relational operator.  */
                    421: int
                    422: relop (op, mode)
                    423:      rtx op;
                    424:      enum machine_mode mode;
                    425: {
                    426:   switch (GET_CODE (op))
                    427:     {
                    428:     case EQ:
                    429:     case NE:
                    430:     case GT:
                    431:     case GE:
                    432:     case LT:
                    433:     case LE:
                    434:     case GTU:
                    435:     case GEU:
                    436:     case LTU:
                    437:     case LEU:
                    438:       return 1;
                    439:     }
                    440:   return 0;
                    441: }
                    442: 
                    443: /* Return truth value of whether OP can be used as an operands in a three
                    444:    address add/subtract insn (such as add %o1,7,%l2) of mode MODE.  */
                    445: 
                    446: int
                    447: arith_operand (op, mode)
                    448:      rtx op;
                    449:      enum machine_mode mode;
                    450: {
                    451:   return (register_operand (op, mode)
                    452:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
                    453: }
                    454: 
                    455: /* Return 1 if OP is a valid first operand for a logical insn of mode MODE.  */
                    456: 
                    457: int
                    458: logic_operand (op, mode)
                    459:      rtx op;
                    460:      enum machine_mode mode;
                    461: {
                    462:   return (register_operand (op, mode)
                    463:          || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
                    464: }
                    465: 
                    466: /* Return 1 if OP is a valid first operand for either a logical insn
                    467:    or an add insn of mode MODE.  */
                    468: 
                    469: int
                    470: compare_operand (op, mode)
                    471:      rtx op;
                    472:      enum machine_mode mode;
                    473: {
                    474:   return (register_operand (op, mode)
                    475:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
                    476: }
                    477: 
                    478: /* Return truth value of whether OP can be used as an operand
                    479:    of a bte insn.  */
                    480: 
                    481: int
                    482: bte_operand (op, mode)
                    483:      rtx op;
                    484:      enum machine_mode mode;
                    485: {
                    486:   return (register_operand (op, mode)
                    487:          || (GET_CODE (op) == CONST_INT
                    488:              && (unsigned) INTVAL (op) < 0x20));
                    489: }
                    490: 
                    491: /* Return 1 if OP is an indexed memory reference of mode MODE.  */
                    492: 
                    493: int
                    494: indexed_operand (op, mode)
                    495:      rtx op;
                    496:      enum machine_mode mode;
                    497: {
                    498:   return (GET_CODE (op) == MEM && GET_MODE (op) == mode
                    499:          && GET_CODE (XEXP (op, 0)) == PLUS
                    500:          && GET_MODE (XEXP (op, 0)) == SImode
                    501:          && register_operand (XEXP (XEXP (op, 0), 0), SImode)
                    502:          && register_operand (XEXP (XEXP (op, 0), 1), SImode));
                    503: }
                    504: 
                    505: /* Return 1 if OP is a suitable source operand for a load insn
                    506:    with mode MODE.  */
                    507: 
                    508: int
                    509: load_operand (op, mode)
                    510:      rtx op;
                    511:      enum machine_mode mode;
                    512: {
                    513:   return (memory_operand (op, mode) || indexed_operand (op, mode));
                    514: }
                    515: 
                    516: /* Return truth value of whether OP is a integer which fits the
                    517:    range constraining immediate operands in add/subtract insns.  */
                    518: 
                    519: int
                    520: small_int (op, mode)
                    521:      rtx op;
                    522:      enum machine_mode mode;
                    523: {
                    524:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
                    525: }
                    526: 
                    527: /* Return truth value of whether OP is a integer which fits the
                    528:    range constraining immediate operands in logic insns.  */
                    529: 
                    530: int
                    531: logic_int (op, mode)
                    532:      rtx op;
                    533:      enum machine_mode mode;
                    534: {
                    535:   return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
                    536: }
                    537: 
                    538: /* Return the best assembler insn template
                    539:    for moving operands[1] into operands[0] as a fullword.  */
                    540: 
                    541: static char *
                    542: singlemove_string (operands)
                    543:      rtx *operands;
                    544: {
                    545:   if (GET_CODE (operands[0]) == MEM)
                    546:     {
                    547:       if (GET_CODE (operands[1]) != MEM)
                    548:        if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
                    549:          {
                    550:            if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    551:                   && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    552:                   && cc_prev_status.mdep == XEXP (operands[0], 0)))
                    553:              output_asm_insn ("orh ha%%%m0,r0,r31", operands);
                    554:            cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    555:            cc_status.mdep = XEXP (operands[0], 0);
                    556:            return "st.l %r1,l%%%m0(r31)";
                    557:          }
                    558:        else
                    559:          return "st.l %r1,%0";
                    560:       else
                    561:        abort ();
                    562: #if 0
                    563:        {
                    564:          rtx xoperands[2];
                    565: 
                    566:          cc_status.flags &= ~CC_F0_IS_0;
                    567:          xoperands[0] = gen_rtx (REG, SFmode, 32);
                    568:          xoperands[1] = operands[1];
                    569:          output_asm_insn (singlemove_string (xoperands), xoperands);
                    570:          xoperands[1] = xoperands[0];
                    571:          xoperands[0] = operands[0];
                    572:          output_asm_insn (singlemove_string (xoperands), xoperands);
                    573:          return "";
                    574:        }
                    575: #endif
                    576:     }
                    577:   if (GET_CODE (operands[1]) == MEM)
                    578:     {
                    579:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
                    580:        {
                    581:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    582:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    583:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                    584:            output_asm_insn ("orh ha%%%m1,r0,r31", operands);
                    585:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    586:          cc_status.mdep = XEXP (operands[1], 0);
                    587:          return "ld.l l%%%m1(r31),%0";
                    588:        }
                    589:       return "ld.l %1,%0";
                    590:     }
                    591:   return "mov %1,%0";
                    592: }
                    593: 
                    594: /* Output assembler code to perform a doubleword move insn
                    595:    with operands OPERANDS.  */
                    596: 
                    597: char *
                    598: output_move_double (operands)
                    599:      rtx *operands;
                    600: {
                    601:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    602:   rtx latehalf[2];
                    603:   rtx addreg0 = 0, addreg1 = 0;
                    604: 
                    605:   /* First classify both operands.  */
                    606: 
                    607:   if (REG_P (operands[0]))
                    608:     optype0 = REGOP;
                    609:   else if (offsettable_memref_p (operands[0]))
                    610:     optype0 = OFFSOP;
                    611:   else if (GET_CODE (operands[0]) == MEM)
                    612:     optype0 = MEMOP;
                    613:   else
                    614:     optype0 = RNDOP;
                    615: 
                    616:   if (REG_P (operands[1]))
                    617:     optype1 = REGOP;
                    618:   else if (CONSTANT_P (operands[1])
                    619:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    620:     optype1 = CNSTOP;
                    621:   else if (offsettable_memref_p (operands[1]))
                    622:     optype1 = OFFSOP;
                    623:   else if (GET_CODE (operands[1]) == MEM)
                    624:     optype1 = MEMOP;
                    625:   else
                    626:     optype1 = RNDOP;
                    627: 
                    628:   /* Check for the cases that the operand constraints are not
                    629:      supposed to allow to happen.  Abort if we get one,
                    630:      because generating code for these cases is painful.  */
                    631: 
                    632:   if (optype0 == RNDOP || optype1 == RNDOP)
                    633:     abort ();
                    634: 
                    635:   /* If an operand is an unoffsettable memory ref, find a register
                    636:      we can increment temporarily to make it refer to the second word.  */
                    637: 
                    638:   if (optype0 == MEMOP)
                    639:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    640: 
                    641:   if (optype1 == MEMOP)
                    642:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    643: 
                    644: /* ??? Perhaps in some cases move double words
                    645:    if there is a spare pair of floating regs.  */
                    646: 
                    647:   /* Ok, we can do one word at a time.
                    648:      Normally we do the low-numbered word first,
                    649:      but if either operand is autodecrementing then we
                    650:      do the high-numbered word first.
                    651: 
                    652:      In either case, set up in LATEHALF the operands to use
                    653:      for the high-numbered word and in some cases alter the
                    654:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    655: 
                    656:   if (optype0 == REGOP)
                    657:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    658:   else if (optype0 == OFFSOP)
                    659:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    660:   else
                    661:     latehalf[0] = operands[0];
                    662: 
                    663:   if (optype1 == REGOP)
                    664:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    665:   else if (optype1 == OFFSOP)
                    666:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    667:   else if (optype1 == CNSTOP)
                    668:     {
                    669:       if (CONSTANT_P (operands[1]))
                    670:        latehalf[1] = const0_rtx;
                    671:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    672:        {
                    673:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
                    674:                                 CONST_DOUBLE_HIGH (operands[1]));
                    675:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    676:                                 CONST_DOUBLE_LOW (operands[1]));
                    677:        }
                    678:     }
                    679:   else
                    680:     latehalf[1] = operands[1];
                    681: 
                    682:   /* If the first move would clobber the source of the second one,
                    683:      do them in the other order.
                    684: 
                    685:      RMS says "This happens only for registers;
                    686:      such overlap can't happen in memory unless the user explicitly
                    687:      sets it up, and that is an undefined circumstance."
                    688: 
                    689:      but it happens on the sparc when loading parameter registers,
                    690:      so I am going to define that circumstance, and make it work
                    691:      as expected.  */
                    692: 
                    693:   if (optype0 == REGOP && optype1 == REGOP
                    694:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    695:     {
                    696:       /* Make any unoffsettable addresses point at high-numbered word.  */
                    697:       if (addreg0)
                    698:        output_asm_insn ("adds 0x4,%0,%0", &addreg0);
                    699:       if (addreg1)
                    700:        output_asm_insn ("adds 0x4,%0,%0", &addreg1);
                    701: 
                    702:       /* Do that word.  */
                    703:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    704: 
                    705:       /* Undo the adds we just did.  */
                    706:       if (addreg0)
                    707:        output_asm_insn ("adds -0x4,%0,%0", &addreg0);
                    708:       if (addreg1)
                    709:        output_asm_insn ("adds -0x4,%0,%0", &addreg1);
                    710: 
                    711:       /* Do low-numbered word.  */
                    712:       return singlemove_string (operands);
                    713:     }
                    714:   else if (optype0 == REGOP && optype1 != REGOP
                    715:           && reg_overlap_mentioned_p (operands[0], operands[1]))
                    716:     {
                    717:       /* Do the late half first.  */
                    718:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    719:       /* Then clobber.  */
                    720:       return singlemove_string (operands);
                    721:     }
                    722: 
                    723:   /* Normal case: do the two words, low-numbered first.  */
                    724: 
                    725:   output_asm_insn (singlemove_string (operands), operands);
                    726: 
                    727:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    728:   if (addreg0)
                    729:     output_asm_insn ("adds 0x4,%0,%0", &addreg0);
                    730:   if (addreg1)
                    731:     output_asm_insn ("adds 0x4,%0,%0", &addreg1);
                    732: 
                    733:   /* Do that word.  */
                    734:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    735: 
                    736:   /* Undo the adds we just did.  */
                    737:   if (addreg0)
                    738:     output_asm_insn ("adds -0x4,%0,%0", &addreg0);
                    739:   if (addreg1)
                    740:     output_asm_insn ("adds -0x4,%0,%0", &addreg1);
                    741: 
                    742:   return "";
                    743: }
                    744: 
                    745: static char *
                    746: output_fp_move_double (operands)
                    747:      rtx *operands;
                    748: {
                    749:   if (FP_REG_P (operands[0]))
                    750:     {
                    751:       if (FP_REG_P (operands[1]))
                    752:        return "fmov.dd %1,%0";
                    753:       if (GET_CODE (operands[1]) == REG)
                    754:        {
                    755:          output_asm_insn ("ixfr %1,%0", operands);
                    756:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    757:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    758:          return "ixfr %1,%0";
                    759:        }
                    760:       if (operands[1] == dconst0_rtx)
                    761:        return "fmov.dd f0,%0";
                    762:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
                    763:        {
                    764:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    765:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    766:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                    767:            output_asm_insn ("orh ha%%%m1,r0,r31", operands);
                    768:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    769:          cc_status.mdep = XEXP (operands[1], 0);
                    770:          return "fld.d l%%%m1(r31),%0";
                    771:        }
                    772:       return "fld.d %1,%0";
                    773:     }
                    774:   else if (FP_REG_P (operands[1]))
                    775:     {
                    776:       if (GET_CODE (operands[0]) == REG)
                    777:        {
                    778:          output_asm_insn ("fxfr %1,%0", operands);
                    779:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    780:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    781:          return "fxfr %1,%0";
                    782:        }
                    783:       if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
                    784:        {
                    785:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    786:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    787:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
                    788:            output_asm_insn ("orh ha%%%m0,r0,r31", operands);
                    789:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    790:          cc_status.mdep = XEXP (operands[0], 0);
                    791:          return "fst.d %1,l%%%m0(r31)";
                    792:        }
                    793:       return "fst.d %1,%0";
                    794:     }
                    795:   else abort ();
                    796: }
                    797: 
                    798: /* Return a REG that occurs in ADDR with coefficient 1.
                    799:    ADDR can be effectively incremented by incrementing REG.  */
                    800: 
                    801: static rtx
                    802: find_addr_reg (addr)
                    803:      rtx addr;
                    804: {
                    805:   while (GET_CODE (addr) == PLUS)
                    806:     {
                    807:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    808:        addr = XEXP (addr, 0);
                    809:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                    810:        addr = XEXP (addr, 1);
                    811:       else if (CONSTANT_P (XEXP (addr, 0)))
                    812:        addr = XEXP (addr, 1);
                    813:       else if (CONSTANT_P (XEXP (addr, 1)))
                    814:        addr = XEXP (addr, 0);
                    815:       else
                    816:        abort ();
                    817:     }
                    818:   if (GET_CODE (addr) == REG)
                    819:     return addr;
                    820:   abort ();
                    821: }
                    822: 
                    823: /* Return a template for a load instruction with mode MODE and
                    824:    arguments from the string ARGS.
                    825: 
                    826:    This string is in static storage.   */
                    827: 
                    828: static char *
                    829: load_opcode (mode, args, reg)
                    830:      enum machine_mode mode;
                    831:      char *args;
                    832:      rtx reg;
                    833: {
                    834:   static char buf[30];
                    835:   char *opcode;
                    836: 
                    837:   switch (mode)
                    838:     {
                    839:     case QImode:
                    840:       opcode = "ld.b";
                    841:       break;
                    842: 
                    843:     case HImode:
                    844:       opcode = "ld.s";
                    845:       break;
                    846: 
                    847:     case SImode:
                    848:     case SFmode:
                    849:       if (FP_REG_P (reg))
                    850:        opcode = "fld.l";
                    851:       else
                    852:        opcode = "ld.l";
                    853:       break;
                    854: 
1.1.1.2 ! root      855:     case DImode:
        !           856:       if (!FP_REG_P (reg))
        !           857:        abort ();
1.1       root      858:     case DFmode:
                    859:       opcode = "fld.d";
                    860:       break;
                    861: 
                    862:     default:
                    863:       abort ();
                    864:     }
                    865: 
                    866:   sprintf (buf, "%s %s", opcode, args);
                    867:   return buf;
                    868: }
                    869: 
                    870: /* Return a template for a store instruction with mode MODE and
                    871:    arguments from the string ARGS.
                    872: 
                    873:    This string is in static storage.   */
                    874: 
                    875: static char *
                    876: store_opcode (mode, args, reg)
                    877:      enum machine_mode mode;
                    878:      char *args;
                    879:      rtx reg;
                    880: {
                    881:   static char buf[30];
                    882:   char *opcode;
                    883: 
                    884:   switch (mode)
                    885:     {
                    886:     case QImode:
                    887:       opcode = "st.b";
                    888:       break;
                    889: 
                    890:     case HImode:
                    891:       opcode = "st.s";
                    892:       break;
                    893: 
                    894:     case SImode:
                    895:     case SFmode:
                    896:       if (FP_REG_P (reg))
                    897:        opcode = "fst.l";
                    898:       else
                    899:        opcode = "st.l";
                    900:       break;
                    901: 
1.1.1.2 ! root      902:     case DImode:
        !           903:       if (!FP_REG_P (reg))
        !           904:        abort ();
1.1       root      905:     case DFmode:
                    906:       opcode = "fst.d";
                    907:       break;
                    908: 
                    909:     default:
                    910:       abort ();
                    911:     }
                    912: 
                    913:   sprintf (buf, "%s %s", opcode, args);
                    914:   return buf;
                    915: }
                    916: 
                    917: /* Output a store-in-memory whose operands are OPERANDS[0,1].
                    918:    OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
                    919: 
                    920:    This function returns a template for an insn.
                    921:    This is in static storage.
                    922: 
                    923:    It may also output some insns directly.
                    924:    It may alter the values of operands[0] and operands[1].  */
                    925: 
                    926: char *
                    927: output_store (operands)
                    928:      rtx *operands;
                    929: {
                    930:   enum machine_mode mode = GET_MODE (operands[0]);
                    931:   rtx address = XEXP (operands[0], 0);
                    932:   char *string;
                    933: 
                    934:   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    935:   cc_status.mdep = address;
                    936: 
                    937:   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    938:         && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    939:         && address == cc_prev_status.mdep))
                    940:     {
                    941:       output_asm_insn ("orh ha%%%m0,r0,r31", operands);
                    942:       cc_prev_status.mdep = address;
                    943:     }
                    944: 
                    945:   /* Store zero in two parts when appropriate.  */
                    946:   if (mode == DFmode && operands[1] == dconst0_rtx)
                    947:     return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);
                    948: 
                    949:   /* Code below isn't smart enough to move a doubleword in two parts,
                    950:      so use output_move_double to do that in the cases that require it.  */
                    951:   if ((mode == DImode || mode == DFmode)
                    952:       && ! FP_REG_P (operands[1]))
                    953:     return output_move_double (operands);
                    954: 
                    955:   return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);
                    956: }
                    957: 
                    958: /* Output a load-from-memory whose operands are OPERANDS[0,1].
                    959:    OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
                    960: 
                    961:    This function returns a template for an insn.
                    962:    This is in static storage.
                    963: 
                    964:    It may also output some insns directly.
                    965:    It may alter the values of operands[0] and operands[1].  */
                    966: 
                    967: char *
                    968: output_load (operands)
                    969:      rtx *operands;
                    970: {
                    971:   enum machine_mode mode = GET_MODE (operands[0]);
                    972:   rtx address = XEXP (operands[1], 0);
                    973: 
                    974:   /* We don't bother trying to see if we know %hi(address).
                    975:      This is because we are doing a load, and if we know the
                    976:      %hi value, we probably also know that value in memory.  */
                    977:   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    978:   cc_status.mdep = address;
                    979: 
                    980:   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    981:         && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    982:         && address == cc_prev_status.mdep
                    983:         && cc_prev_status.mdep == cc_status.mdep))
                    984:     {
                    985:       output_asm_insn ("orh ha%%%m1,r0,r31", operands);
                    986:       cc_prev_status.mdep = address;
                    987:     }
                    988: 
                    989:   /* Code below isn't smart enough to move a doubleword in two parts,
                    990:      so use output_move_double to do that in the cases that require it.  */
                    991:   if ((mode == DImode || mode == DFmode)
                    992:       && ! FP_REG_P (operands[0]))
                    993:     return output_move_double (operands);
                    994: 
                    995:   return load_opcode (mode, "l%%%m1(r31),%0", operands[0]);
                    996: }
                    997: 
                    998: /* Load the address specified by OPERANDS[3] into the register
                    999:    specified by OPERANDS[0].
                   1000: 
                   1001:    OPERANDS[3] may be the result of a sum, hence it could either be:
                   1002: 
                   1003:    (1) CONST
                   1004:    (2) REG
                   1005:    (2) REG + CONST_INT
                   1006:    (3) REG + REG + CONST_INT
                   1007:    (4) REG + REG  (special case of 3).
                   1008: 
                   1009:    Note that (3) is not a legitimate address.
                   1010:    All cases are handled here.  */
                   1011: 
                   1012: void
                   1013: output_load_address (operands)
                   1014:      rtx *operands;
                   1015: {
                   1016:   rtx base, offset;
                   1017: 
                   1018:   if (CONSTANT_P (operands[3]))
                   1019:     {
                   1020:       output_asm_insn ("mov %3,%0", operands);
                   1021:       return;
                   1022:     }
                   1023: 
                   1024:   if (REG_P (operands[3]))
                   1025:     {
                   1026:       if (REGNO (operands[0]) != REGNO (operands[3]))
                   1027:        output_asm_insn ("mov %3,%0", operands);
                   1028:       return;
                   1029:     }
                   1030: 
                   1031:   if (GET_CODE (operands[3]) != PLUS)
                   1032:     abort ();
                   1033: 
                   1034:   base = XEXP (operands[3], 0);
                   1035:   offset = XEXP (operands[3], 1);
                   1036: 
                   1037:   if (GET_CODE (base) == CONST_INT)
                   1038:     {
                   1039:       rtx tmp = base;
                   1040:       base = offset;
                   1041:       offset = tmp;
                   1042:     }
                   1043: 
                   1044:   if (GET_CODE (offset) != CONST_INT)
                   1045:     {
                   1046:       /* Operand is (PLUS (REG) (REG)).  */
                   1047:       base = operands[3];
                   1048:       offset = const0_rtx;
                   1049:     }
                   1050: 
                   1051:   if (REG_P (base))
                   1052:     {
                   1053:       operands[6] = base;
                   1054:       operands[7] = offset;
                   1055:       if (SMALL_INT (offset))
                   1056:        output_asm_insn ("adds %7,%6,%0", operands);
                   1057:       else
                   1058:        output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
                   1059:     }
                   1060:   else if (GET_CODE (base) == PLUS)
                   1061:     {
                   1062:       operands[6] = XEXP (base, 0);
                   1063:       operands[7] = XEXP (base, 1);
                   1064:       operands[8] = offset;
                   1065: 
                   1066:       if (SMALL_INT (offset))
                   1067:        output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
                   1068:       else
                   1069:        output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
                   1070:     }
                   1071:   else
                   1072:     abort ();
                   1073: }
                   1074: 
                   1075: /* Output code to place a size count SIZE in register REG.
                   1076:    Because block moves are pipelined, we don't include the
                   1077:    first element in the transfer of SIZE to REG.
                   1078:    For this, we subtract ALIGN.  (Actually, I think it is not
                   1079:    right to subtract on this machine, so right now we don't.)  */
                   1080: 
                   1081: static void
                   1082: output_size_for_block_move (size, reg, align)
                   1083:      rtx size, reg, align;
                   1084: {
                   1085:   rtx xoperands[3];
                   1086: 
                   1087:   xoperands[0] = reg;
                   1088:   xoperands[1] = size;
                   1089:   xoperands[2] = align;
                   1090: 
                   1091: #if 1
                   1092:   cc_status.flags &= ~ CC_KNOW_HI_R31;
                   1093:   output_asm_insn ("mov %1,%0", xoperands);
                   1094: #else
                   1095:   if (GET_CODE (size) == REG)
                   1096:     output_asm_insn ("sub %2,%1,%0", xoperands);
                   1097:   else
                   1098:     {
                   1099:       xoperands[1]
                   1100:        = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
                   1101:       cc_status.flags &= ~ CC_KNOW_HI_R31;
                   1102:       output_asm_insn ("mov %1,%0", xoperands);
                   1103:     }
                   1104: #endif
                   1105: }
                   1106: 
                   1107: /* Emit code to perform a block move.
                   1108: 
                   1109:    OPERANDS[0] is the destination.
                   1110:    OPERANDS[1] is the source.
                   1111:    OPERANDS[2] is the size.
                   1112:    OPERANDS[3] is the known safe alignment.
                   1113:    OPERANDS[4..6] are pseudos we can safely clobber as temps.  */
                   1114: 
                   1115: char *
                   1116: output_block_move (operands)
                   1117:      rtx *operands;
                   1118: {
                   1119:   /* A vector for our computed operands.  Note that load_output_address
                   1120:      makes use of (and can clobber) up to the 8th element of this vector.  */
                   1121:   rtx xoperands[10];
                   1122:   rtx zoperands[10];
                   1123:   static int movstrsi_label = 0;
                   1124:   int i, j;
                   1125:   rtx temp1 = operands[4];
                   1126:   rtx alignrtx = operands[3];
                   1127:   int align = INTVAL (alignrtx);
                   1128: 
                   1129:   xoperands[0] = operands[0];
                   1130:   xoperands[1] = operands[1];
                   1131:   xoperands[2] = temp1;
                   1132: 
                   1133:   /* We can't move more than four bytes at a time
                   1134:      because we have only one register to move them through.  */
                   1135:   if (align > 4)
                   1136:     {
                   1137:       align = 4;
                   1138:       alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
                   1139:     }
                   1140: 
                   1141:   /* Since we clobber untold things, nix the condition codes.  */
                   1142:   CC_STATUS_INIT;
                   1143: 
                   1144:   /* Recognize special cases of block moves.  These occur
                   1145:      when GNU C++ is forced to treat something as BLKmode
                   1146:      to keep it in memory, when its mode could be represented
                   1147:      with something smaller.
                   1148: 
                   1149:      We cannot do this for global variables, since we don't know
                   1150:      what pages they don't cross.  Sigh.  */
                   1151:   if (GET_CODE (operands[2]) == CONST_INT
                   1152:       && INTVAL (operands[2]) <= 16
                   1153:       && ! CONSTANT_ADDRESS_P (operands[0])
                   1154:       && ! CONSTANT_ADDRESS_P (operands[1]))
                   1155:     {
                   1156:       int size = INTVAL (operands[2]);
                   1157:       rtx op0 = xoperands[0];
                   1158:       rtx op1 = xoperands[1];
                   1159: 
                   1160:       cc_status.flags &= ~CC_KNOW_HI_R31;
                   1161:       if (align == 1)
                   1162:        {
                   1163:          if (memory_address_p (QImode, plus_constant (op0, size))
                   1164:              && memory_address_p (QImode, plus_constant (op1, size)))
                   1165:            {
                   1166:              for (i = size-1; i >= 0; i--)
                   1167:                {
                   1168:                  xoperands[0] = plus_constant (op0, i);
                   1169:                  xoperands[1] = plus_constant (op1, i);
                   1170:                  output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
                   1171:                                   xoperands);
                   1172:                }
                   1173:              return "";
                   1174:            }
                   1175:        }
                   1176:       else if (align == 2)
                   1177:        {
                   1178:          if (memory_address_p (HImode, plus_constant (op0, size))
                   1179:              && memory_address_p (HImode, plus_constant (op1, size)))
                   1180:            {
                   1181:              for (i = (size>>1)-1; i >= 0; i--)
                   1182:                {
                   1183:                  xoperands[0] = plus_constant (op0, i * 2);
                   1184:                  xoperands[1] = plus_constant (op1, i * 2);
                   1185:                  output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
                   1186:                                   xoperands);
                   1187:                }
                   1188:              return "";
                   1189:            }
                   1190:        }
                   1191:       else
                   1192:        {
                   1193:          if (memory_address_p (SImode, plus_constant (op0, size))
                   1194:              && memory_address_p (SImode, plus_constant (op1, size)))
                   1195:            {
                   1196:              for (i = (size>>2)-1; i >= 0; i--)
                   1197:                {
                   1198:                  xoperands[0] = plus_constant (op0, i * 4);
                   1199:                  xoperands[1] = plus_constant (op1, i * 4);
                   1200:                  output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
                   1201:                                   xoperands);
                   1202:                }
                   1203:              return "";
                   1204:            }
                   1205:        }
                   1206:     }
                   1207: 
                   1208:   /* This is the size of the transfer.
                   1209:      Either use the register which already contains the size,
                   1210:      or use a free register (used by no operands).  */
                   1211:   output_size_for_block_move (operands[2], operands[4], alignrtx);
                   1212: 
                   1213: #if 0
                   1214:   /* Also emit code to decrement the size value by ALIGN.  */
                   1215:   zoperands[0] = operands[0];
                   1216:   zoperands[3] = plus_constant (operands[0], align);
                   1217:   output_load_address (zoperands);
                   1218: #endif
                   1219: 
                   1220:   /* Generate number for unique label.  */
                   1221: 
                   1222:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1223: 
                   1224:   /* Copy the increment (negative) to a register for bla insn.  */
                   1225: 
                   1226:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
                   1227:   xoperands[5] = operands[5];
                   1228:   output_asm_insn ("mov %4,%5", xoperands);
                   1229: 
                   1230:   xoperands[6] = operands[6];
                   1231:   output_asm_insn ("adds %0,%2,%6", xoperands);
                   1232: 
                   1233:   /* Now the actual loop.
                   1234:      In xoperands, elements 1 and 0 are the input and output vectors.
                   1235:      Element 2 is the loop index.  Element 5 is the increment.  */
                   1236: 
                   1237:   if (align == 1)
                   1238:     {
                   1239:       output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
                   1240:       output_asm_insn ("ld.b %1(%2),r31", xoperands);
                   1241:       output_asm_insn ("adds %5,%6,%6", xoperands);
                   1242:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
                   1243:       output_asm_insn ("st.b r31,0(%6)", xoperands);
                   1244:     }
                   1245:   if (align == 2)
                   1246:     {
                   1247:       output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
                   1248:       output_asm_insn ("ld.s %1(%2),r31", xoperands);
                   1249:       output_asm_insn ("adds %5,%6,%6", xoperands);
                   1250:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
                   1251:       output_asm_insn ("st.s r31,0(%6)", xoperands);
                   1252:     }
                   1253:   if (align == 4)
                   1254:     {
                   1255:       output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
                   1256:       output_asm_insn ("ld.l %1(%2),r31", xoperands);
                   1257:       output_asm_insn ("adds %5,%6,%6", xoperands);
                   1258:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
                   1259:       output_asm_insn ("st.l r31,0(%6)", xoperands);
                   1260:     }
                   1261: 
                   1262:   return "";
                   1263: }
                   1264: 
                   1265: /* Output a delayed branch insn with the delay insn in its
                   1266:    branch slot.  The delayed branch insn template is in TEMPLATE,
                   1267:    with operands OPERANDS.  The insn in its delay slot is INSN.
                   1268: 
                   1269:    As a special case, since we know that all memory transfers are via
                   1270:    ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
                   1271:    reference around the branch as
                   1272: 
                   1273:        orh ha%x,r0,r31
                   1274:        b ...
                   1275:        ld/st l%x(r31),...
                   1276: 
                   1277:    As another special case, we handle loading (SYMBOL_REF ...) and
                   1278:    other large constants around branches as well:
                   1279: 
                   1280:        orh h%x,r0,%0
                   1281:        b ...
                   1282:        or l%x,%0,%1
                   1283: 
                   1284:    */
                   1285: 
                   1286: char *
                   1287: output_delayed_branch (template, operands, insn)
                   1288:      char *template;
                   1289:      rtx *operands;
                   1290:      rtx insn;
                   1291: {
                   1292:   extern rtx recog_operand[];
                   1293:   rtx src = XVECEXP (PATTERN (insn), 0, 1);
                   1294:   rtx dest = XVECEXP (PATTERN (insn), 0, 0);
                   1295: 
                   1296:   if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
                   1297:       || (GET_CODE (src) == CONST_INT
                   1298:          && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0)))
                   1299:     {
                   1300:       rtx xoperands[2];
                   1301:       xoperands[0] = dest;
                   1302:       xoperands[1] = src;
                   1303: 
                   1304:       /* Output the `orh' insn.  */
                   1305:       output_asm_insn ("orh h%%%1,r0,%0", xoperands);
                   1306: 
                   1307:       /* Output the branch instruction next.  */
                   1308:       output_asm_insn (template, operands);
                   1309: 
                   1310:       /* Now output the `or' insn.  */
                   1311:       output_asm_insn ("or l%%%1,%0,%0", xoperands);
                   1312:     }
                   1313:   else if ((GET_CODE (src) == MEM
                   1314:            && CONSTANT_ADDRESS_P (XEXP (src, 0)))
                   1315:           || (GET_CODE (dest) == MEM
                   1316:               && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
                   1317:     {
                   1318:       rtx xoperands[2];
                   1319:       char *split_template;
                   1320:       xoperands[0] = dest;
                   1321:       xoperands[1] = src;
                   1322: 
                   1323:       /* Output the `orh' insn.  */
                   1324:       if (GET_CODE (src) == MEM)
                   1325:        {
                   1326:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                   1327:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                   1328:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                   1329:            output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
                   1330:          split_template = load_opcode (GET_MODE (dest),
                   1331:                                        "l%%%m1(r31),%0", src);
                   1332:        }
                   1333:       else
                   1334:        {
                   1335:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                   1336:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                   1337:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
                   1338:            output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
                   1339:          split_template = store_opcode (GET_MODE (dest),
                   1340:                                         "%r1,l%%%m0(r31)", src);
                   1341:        }
                   1342: 
                   1343:       /* Output the branch instruction next.  */
                   1344:       output_asm_insn (template, operands);
                   1345: 
                   1346:       /* Now output the load or store.
                   1347:         No need to do a CC_STATUS_INIT, because we are branching anyway.  */
                   1348:       output_asm_insn (split_template, xoperands);
                   1349:     }
                   1350:   else
                   1351:     {
                   1352:       extern char *insn_template[];
                   1353:       extern char *(*insn_outfun[])();
                   1354:       extern int insn_n_operands[];
                   1355:       extern rtx alter_subreg();
                   1356:       int insn_code_number;
                   1357:       rtx pat = gen_rtx (SET, VOIDmode, dest, src);
                   1358:       rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
                   1359:       int i;
                   1360: 
                   1361:       /* Output the branch instruction first.  */
                   1362:       output_asm_insn (template, operands);
                   1363: 
                   1364:       /* Now recognize the insn which we put in its delay slot.
                   1365:         We must do this after outputing the branch insn,
                   1366:         since operands may just be a pointer to `recog_operand'.  */
                   1367:       insn_code_number = recog (pat, delay_insn);
                   1368:       if (insn_code_number == -1)
                   1369:        abort ();
                   1370: 
                   1371:       for (i = 0; i < insn_n_operands[insn_code_number]; i++)
                   1372:        {
                   1373:          if (GET_CODE (recog_operand[i]) == SUBREG)
                   1374:            recog_operand[i] = alter_subreg (recog_operand[i]);
                   1375:        }
                   1376: 
                   1377:       /* Now get the template for what this insn would
                   1378:         have been, without the branch.  Its operands are
                   1379:         exactly the same as they would be, so we don't
                   1380:         need to do an insn_extract.  */
                   1381:       template = insn_template[insn_code_number];
                   1382:       if (template == 0)
                   1383:        template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
                   1384:       output_asm_insn (template, recog_operand);
                   1385:     }
                   1386:   CC_STATUS_INIT;
                   1387:   return "";
                   1388: }
                   1389: 
                   1390: /* Output a newly constructed insn DELAY_INSN.  */
                   1391: char *
                   1392: output_delay_insn (delay_insn)
                   1393:      rtx delay_insn;
                   1394: {
                   1395:   char *template;
                   1396:   extern rtx recog_operand[];
                   1397:   extern char call_used_regs[];
                   1398:   extern char *insn_template[];
                   1399:   extern int insn_n_operands[];
                   1400:   extern char *(*insn_outfun[])();
                   1401:   extern rtx alter_subreg();
                   1402:   int insn_code_number;
                   1403:   extern int insn_n_operands[];
                   1404:   int i;
                   1405: 
                   1406:   /* Now recognize the insn which we put in its delay slot.
                   1407:      We must do this after outputing the branch insn,
                   1408:      since operands may just be a pointer to `recog_operand'.  */
                   1409:   insn_code_number = recog_memoized (delay_insn);
                   1410:   if (insn_code_number == -1)
                   1411:     abort ();
                   1412: 
                   1413:   /* Extract the operands of this delay insn.  */
                   1414:   INSN_CODE (delay_insn) = insn_code_number;
                   1415:   insn_extract (delay_insn);
                   1416: 
                   1417:   /* It is possible that this insn has not been properly scaned by final
                   1418:      yet.  If this insn's operands don't appear in the peephole's
                   1419:      actual operands, then they won't be fixed up by final, so we
                   1420:      make sure they get fixed up here.  -- This is a kludge.  */
                   1421:   for (i = 0; i < insn_n_operands[insn_code_number]; i++)
                   1422:     {
                   1423:       if (GET_CODE (recog_operand[i]) == SUBREG)
                   1424:        recog_operand[i] = alter_subreg (recog_operand[i]);
                   1425:     }
                   1426: 
                   1427: #ifdef REGISTER_CONSTRAINTS
                   1428:   if (! constrain_operands (insn_code_number))
                   1429:     abort ();
                   1430: #endif
                   1431: 
                   1432:   cc_prev_status = cc_status;
                   1433: 
                   1434:   /* Update `cc_status' for this instruction.
                   1435:      The instruction's output routine may change it further.
                   1436:      If the output routine for a jump insn needs to depend
                   1437:      on the cc status, it should look at cc_prev_status.  */
                   1438: 
                   1439:   NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
                   1440: 
                   1441:   /* Now get the template for what this insn would
                   1442:      have been, without the branch.  */
                   1443: 
                   1444:   template = insn_template[insn_code_number];
                   1445:   if (template == 0)
                   1446:     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
                   1447:   output_asm_insn (template, recog_operand);
                   1448:   return "";
                   1449: }
                   1450: 

unix.superglobalmegacorp.com

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