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

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: 
1.1.1.3   root      278:     case PLUS:
                    279:     case MINUS:
                    280:       /* Detect cases that require multiple instructions.  */
                    281:       if (CONSTANT_P (XEXP (op, 1))
                    282:          && !(GET_CODE (XEXP (op, 1)) == CONST_INT
                    283:               && SMALL_INT (XEXP (op, 1))))
                    284:        return 0;
1.1       root      285:     case EQ:
                    286:     case NE:
                    287:     case LT:
                    288:     case GT:
                    289:     case LE:
                    290:     case GE:
                    291:     case LTU:
                    292:     case GTU:
                    293:     case LEU:
                    294:     case GEU:
                    295:       /* Not doing floating point, since they probably
                    296:         take longer than the branch slot they might fill.  */
                    297:       return (mode != SFmode && mode != DFmode);
1.1.1.3   root      298: 
1.1       root      299:     case AND:
1.1.1.3   root      300:       if (GET_CODE (XEXP (op, 1)) == NOT)
                    301:        {
                    302:          rtx arg = XEXP (XEXP (op, 1), 0);
                    303:          if (CONSTANT_P (arg)
                    304:              && !(GET_CODE (arg) == CONST_INT
                    305:                   && (SMALL_INT (arg)
                    306:                       || INTVAL (arg) & 0xffff == 0)))
                    307:            return 0;
                    308:        }
1.1       root      309:     case IOR:
                    310:     case XOR:
1.1.1.3   root      311:       /* Both small and round numbers take one instruction;
                    312:         others take two.  */
                    313:       if (CONSTANT_P (XEXP (op, 1))
                    314:          && !(GET_CODE (XEXP (op, 1)) == CONST_INT
                    315:               && (SMALL_INT (XEXP (op, 1))
                    316:                   || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
                    317:        return 0;
                    318: 
1.1       root      319:     case LSHIFT:
                    320:     case ASHIFT:
                    321:     case ASHIFTRT:
                    322:     case LSHIFTRT:
                    323:       return 1;
                    324: 
                    325:     case SUBREG:
                    326:       if (SUBREG_WORD (op) != 0)
                    327:        return 0;
                    328:       return single_insn_src_p (SUBREG_REG (op), mode);
                    329: 
                    330:       /* Not doing floating point, since they probably
                    331:         take longer than the branch slot they might fill.  */
                    332:     case FLOAT_EXTEND:
                    333:     case FLOAT_TRUNCATE:
                    334:     case FLOAT:
                    335:     case FIX:
                    336:     case UNSIGNED_FLOAT:
                    337:     case UNSIGNED_FIX:
                    338:       return 0;
                    339: 
                    340:     default:
                    341:       return 0;
                    342:     }
                    343: }
                    344: 
                    345: /* Nonzero only if this *really* is a single insn operand.  */
                    346: int
                    347: strict_single_insn_op_p (op, mode)
                    348:      rtx op;
                    349:      enum machine_mode mode;
                    350: {
                    351:   if (mode == VOIDmode)
                    352:     mode = GET_MODE (op);
                    353: 
                    354:   switch (GET_CODE (op))
                    355:     {
                    356:     case CC0:
                    357:       return 1;
                    358: 
                    359:     case CONST_INT:
                    360:       if (SMALL_INT (op))
                    361:        return 1;
                    362:       /* We can put this set insn into delay slot, because this is one
1.1.1.4 ! root      363:         insn; `orh'.  */
        !           364:       if ((INTVAL (op) & 0xffff) == 0)
1.1       root      365:        return 1;
                    366:       return 0;
                    367: 
                    368:     case SYMBOL_REF:
                    369:       return 0;
                    370: 
                    371:     case REG:
                    372: #if 0
                    373:       /* This loses when moving an freg to a general reg.  */
                    374:       return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
                    375: #endif
                    376:       return (mode != DFmode && mode != DImode);
                    377: 
                    378:     case MEM:
                    379:       if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
                    380:        return (mode != DFmode && mode != DImode);
                    381:       return 0;
                    382: 
                    383:       /* We never need to negate or complement constants.  */
                    384:     case NEG:
                    385:       return (mode != DFmode);
                    386:     case NOT:
                    387:     case ZERO_EXTEND:
                    388:       return 1;
                    389: 
1.1.1.3   root      390:     case PLUS:
                    391:     case MINUS:
                    392:       /* Detect cases that require multiple instructions.  */
                    393:       if (CONSTANT_P (XEXP (op, 1))
                    394:          && !(GET_CODE (XEXP (op, 1)) == CONST_INT
                    395:               && SMALL_INT (XEXP (op, 1))))
                    396:        return 0;
1.1       root      397:     case EQ:
                    398:     case NE:
                    399:     case LT:
                    400:     case GT:
                    401:     case LE:
                    402:     case GE:
                    403:     case LTU:
                    404:     case GTU:
                    405:     case LEU:
                    406:     case GEU:
1.1.1.3   root      407:       return 1;
                    408: 
1.1       root      409:     case AND:
1.1.1.3   root      410:       if (GET_CODE (XEXP (op, 1)) == NOT)
                    411:        {
                    412:          rtx arg = XEXP (XEXP (op, 1), 0);
                    413:          if (CONSTANT_P (arg)
                    414:              && !(GET_CODE (arg) == CONST_INT
                    415:                   && (SMALL_INT (arg)
                    416:                       || INTVAL (arg) & 0xffff == 0)))
                    417:            return 0;
                    418:        }
1.1       root      419:     case IOR:
                    420:     case XOR:
1.1.1.3   root      421:       /* Both small and round numbers take one instruction;
                    422:         others take two.  */
                    423:       if (CONSTANT_P (XEXP (op, 1))
                    424:          && !(GET_CODE (XEXP (op, 1)) == CONST_INT
                    425:               && (SMALL_INT (XEXP (op, 1))
                    426:                   || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
                    427:        return 0;
1.1       root      428:     case LSHIFT:
                    429:     case ASHIFT:
                    430:     case ASHIFTRT:
                    431:     case LSHIFTRT:
                    432:       return 1;
                    433: 
                    434:     case SUBREG:
                    435:       if (SUBREG_WORD (op) != 0)
                    436:        return 0;
                    437:       return strict_single_insn_op_p (SUBREG_REG (op), mode);
                    438: 
                    439:     case SIGN_EXTEND:
                    440:       if (GET_CODE (XEXP (op, 0)) == MEM
                    441:          && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
                    442:        return 1;
                    443:       return 0;
                    444: 
                    445:       /* Not doing floating point, since they probably
                    446:         take longer than the branch slot they might fill.  */
                    447:     case FLOAT_EXTEND:
                    448:     case FLOAT_TRUNCATE:
                    449:     case FLOAT:
                    450:     case FIX:
                    451:     case UNSIGNED_FLOAT:
                    452:     case UNSIGNED_FIX:
                    453:       return 0;
                    454: 
                    455:     default:
                    456:       return 0;
                    457:     }
                    458: }
                    459: 
                    460: /* Return truth value of whether OP is a relational operator.  */
                    461: int
                    462: relop (op, mode)
                    463:      rtx op;
                    464:      enum machine_mode mode;
                    465: {
                    466:   switch (GET_CODE (op))
                    467:     {
                    468:     case EQ:
                    469:     case NE:
                    470:     case GT:
                    471:     case GE:
                    472:     case LT:
                    473:     case LE:
                    474:     case GTU:
                    475:     case GEU:
                    476:     case LTU:
                    477:     case LEU:
                    478:       return 1;
                    479:     }
                    480:   return 0;
                    481: }
                    482: 
                    483: /* Return truth value of whether OP can be used as an operands in a three
                    484:    address add/subtract insn (such as add %o1,7,%l2) of mode MODE.  */
                    485: 
                    486: int
                    487: arith_operand (op, mode)
                    488:      rtx op;
                    489:      enum machine_mode mode;
                    490: {
                    491:   return (register_operand (op, mode)
                    492:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
                    493: }
                    494: 
                    495: /* Return 1 if OP is a valid first operand for a logical insn of mode MODE.  */
                    496: 
                    497: int
                    498: logic_operand (op, mode)
                    499:      rtx op;
                    500:      enum machine_mode mode;
                    501: {
                    502:   return (register_operand (op, mode)
                    503:          || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
                    504: }
                    505: 
                    506: /* Return 1 if OP is a valid first operand for either a logical insn
                    507:    or an add insn of mode MODE.  */
                    508: 
                    509: int
                    510: compare_operand (op, mode)
                    511:      rtx op;
                    512:      enum machine_mode mode;
                    513: {
                    514:   return (register_operand (op, mode)
                    515:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
                    516: }
                    517: 
                    518: /* Return truth value of whether OP can be used as an operand
                    519:    of a bte insn.  */
                    520: 
                    521: int
                    522: bte_operand (op, mode)
                    523:      rtx op;
                    524:      enum machine_mode mode;
                    525: {
                    526:   return (register_operand (op, mode)
                    527:          || (GET_CODE (op) == CONST_INT
                    528:              && (unsigned) INTVAL (op) < 0x20));
                    529: }
                    530: 
                    531: /* Return 1 if OP is an indexed memory reference of mode MODE.  */
                    532: 
                    533: int
                    534: indexed_operand (op, mode)
                    535:      rtx op;
                    536:      enum machine_mode mode;
                    537: {
                    538:   return (GET_CODE (op) == MEM && GET_MODE (op) == mode
                    539:          && GET_CODE (XEXP (op, 0)) == PLUS
                    540:          && GET_MODE (XEXP (op, 0)) == SImode
                    541:          && register_operand (XEXP (XEXP (op, 0), 0), SImode)
                    542:          && register_operand (XEXP (XEXP (op, 0), 1), SImode));
                    543: }
                    544: 
                    545: /* Return 1 if OP is a suitable source operand for a load insn
                    546:    with mode MODE.  */
                    547: 
                    548: int
                    549: load_operand (op, mode)
                    550:      rtx op;
                    551:      enum machine_mode mode;
                    552: {
                    553:   return (memory_operand (op, mode) || indexed_operand (op, mode));
                    554: }
                    555: 
                    556: /* Return truth value of whether OP is a integer which fits the
                    557:    range constraining immediate operands in add/subtract insns.  */
                    558: 
                    559: int
                    560: small_int (op, mode)
                    561:      rtx op;
                    562:      enum machine_mode mode;
                    563: {
                    564:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
                    565: }
                    566: 
                    567: /* Return truth value of whether OP is a integer which fits the
                    568:    range constraining immediate operands in logic insns.  */
                    569: 
                    570: int
                    571: logic_int (op, mode)
                    572:      rtx op;
                    573:      enum machine_mode mode;
                    574: {
                    575:   return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
                    576: }
                    577: 
                    578: /* Return the best assembler insn template
                    579:    for moving operands[1] into operands[0] as a fullword.  */
                    580: 
                    581: static char *
                    582: singlemove_string (operands)
                    583:      rtx *operands;
                    584: {
                    585:   if (GET_CODE (operands[0]) == MEM)
                    586:     {
                    587:       if (GET_CODE (operands[1]) != MEM)
                    588:        if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
                    589:          {
                    590:            if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    591:                   && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    592:                   && cc_prev_status.mdep == XEXP (operands[0], 0)))
                    593:              output_asm_insn ("orh ha%%%m0,r0,r31", operands);
                    594:            cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    595:            cc_status.mdep = XEXP (operands[0], 0);
                    596:            return "st.l %r1,l%%%m0(r31)";
                    597:          }
                    598:        else
                    599:          return "st.l %r1,%0";
                    600:       else
                    601:        abort ();
                    602: #if 0
                    603:        {
                    604:          rtx xoperands[2];
                    605: 
                    606:          cc_status.flags &= ~CC_F0_IS_0;
                    607:          xoperands[0] = gen_rtx (REG, SFmode, 32);
                    608:          xoperands[1] = operands[1];
                    609:          output_asm_insn (singlemove_string (xoperands), xoperands);
                    610:          xoperands[1] = xoperands[0];
                    611:          xoperands[0] = operands[0];
                    612:          output_asm_insn (singlemove_string (xoperands), xoperands);
                    613:          return "";
                    614:        }
                    615: #endif
                    616:     }
                    617:   if (GET_CODE (operands[1]) == MEM)
                    618:     {
                    619:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
                    620:        {
                    621:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    622:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    623:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                    624:            output_asm_insn ("orh ha%%%m1,r0,r31", operands);
                    625:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    626:          cc_status.mdep = XEXP (operands[1], 0);
                    627:          return "ld.l l%%%m1(r31),%0";
                    628:        }
                    629:       return "ld.l %1,%0";
                    630:     }
                    631:   return "mov %1,%0";
                    632: }
                    633: 
                    634: /* Output assembler code to perform a doubleword move insn
                    635:    with operands OPERANDS.  */
                    636: 
                    637: char *
                    638: output_move_double (operands)
                    639:      rtx *operands;
                    640: {
                    641:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    642:   rtx latehalf[2];
                    643:   rtx addreg0 = 0, addreg1 = 0;
                    644: 
                    645:   /* First classify both operands.  */
                    646: 
                    647:   if (REG_P (operands[0]))
                    648:     optype0 = REGOP;
                    649:   else if (offsettable_memref_p (operands[0]))
                    650:     optype0 = OFFSOP;
                    651:   else if (GET_CODE (operands[0]) == MEM)
                    652:     optype0 = MEMOP;
                    653:   else
                    654:     optype0 = RNDOP;
                    655: 
                    656:   if (REG_P (operands[1]))
                    657:     optype1 = REGOP;
                    658:   else if (CONSTANT_P (operands[1])
                    659:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    660:     optype1 = CNSTOP;
                    661:   else if (offsettable_memref_p (operands[1]))
                    662:     optype1 = OFFSOP;
                    663:   else if (GET_CODE (operands[1]) == MEM)
                    664:     optype1 = MEMOP;
                    665:   else
                    666:     optype1 = RNDOP;
                    667: 
                    668:   /* Check for the cases that the operand constraints are not
                    669:      supposed to allow to happen.  Abort if we get one,
                    670:      because generating code for these cases is painful.  */
                    671: 
                    672:   if (optype0 == RNDOP || optype1 == RNDOP)
                    673:     abort ();
                    674: 
                    675:   /* If an operand is an unoffsettable memory ref, find a register
                    676:      we can increment temporarily to make it refer to the second word.  */
                    677: 
                    678:   if (optype0 == MEMOP)
                    679:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    680: 
                    681:   if (optype1 == MEMOP)
                    682:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    683: 
                    684: /* ??? Perhaps in some cases move double words
                    685:    if there is a spare pair of floating regs.  */
                    686: 
                    687:   /* Ok, we can do one word at a time.
                    688:      Normally we do the low-numbered word first,
                    689:      but if either operand is autodecrementing then we
                    690:      do the high-numbered word first.
                    691: 
                    692:      In either case, set up in LATEHALF the operands to use
                    693:      for the high-numbered word and in some cases alter the
                    694:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    695: 
                    696:   if (optype0 == REGOP)
                    697:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    698:   else if (optype0 == OFFSOP)
                    699:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    700:   else
                    701:     latehalf[0] = operands[0];
                    702: 
                    703:   if (optype1 == REGOP)
                    704:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    705:   else if (optype1 == OFFSOP)
                    706:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    707:   else if (optype1 == CNSTOP)
                    708:     {
                    709:       if (CONSTANT_P (operands[1]))
                    710:        latehalf[1] = const0_rtx;
                    711:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    712:        {
                    713:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
                    714:                                 CONST_DOUBLE_HIGH (operands[1]));
                    715:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    716:                                 CONST_DOUBLE_LOW (operands[1]));
                    717:        }
                    718:     }
                    719:   else
                    720:     latehalf[1] = operands[1];
                    721: 
                    722:   /* If the first move would clobber the source of the second one,
                    723:      do them in the other order.
                    724: 
                    725:      RMS says "This happens only for registers;
                    726:      such overlap can't happen in memory unless the user explicitly
                    727:      sets it up, and that is an undefined circumstance."
                    728: 
                    729:      but it happens on the sparc when loading parameter registers,
                    730:      so I am going to define that circumstance, and make it work
                    731:      as expected.  */
                    732: 
                    733:   if (optype0 == REGOP && optype1 == REGOP
                    734:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    735:     {
                    736:       /* Make any unoffsettable addresses point at high-numbered word.  */
                    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:       /* Do that word.  */
                    743:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    744: 
                    745:       /* Undo the adds we just did.  */
                    746:       if (addreg0)
                    747:        output_asm_insn ("adds -0x4,%0,%0", &addreg0);
                    748:       if (addreg1)
                    749:        output_asm_insn ("adds -0x4,%0,%0", &addreg1);
                    750: 
                    751:       /* Do low-numbered word.  */
                    752:       return singlemove_string (operands);
                    753:     }
                    754:   else if (optype0 == REGOP && optype1 != REGOP
                    755:           && reg_overlap_mentioned_p (operands[0], operands[1]))
                    756:     {
                    757:       /* Do the late half first.  */
                    758:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    759:       /* Then clobber.  */
                    760:       return singlemove_string (operands);
                    761:     }
                    762: 
                    763:   /* Normal case: do the two words, low-numbered first.  */
                    764: 
                    765:   output_asm_insn (singlemove_string (operands), operands);
                    766: 
                    767:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    768:   if (addreg0)
                    769:     output_asm_insn ("adds 0x4,%0,%0", &addreg0);
                    770:   if (addreg1)
                    771:     output_asm_insn ("adds 0x4,%0,%0", &addreg1);
                    772: 
                    773:   /* Do that word.  */
                    774:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    775: 
                    776:   /* Undo the adds we just did.  */
                    777:   if (addreg0)
                    778:     output_asm_insn ("adds -0x4,%0,%0", &addreg0);
                    779:   if (addreg1)
                    780:     output_asm_insn ("adds -0x4,%0,%0", &addreg1);
                    781: 
                    782:   return "";
                    783: }
                    784: 
                    785: static char *
                    786: output_fp_move_double (operands)
                    787:      rtx *operands;
                    788: {
                    789:   if (FP_REG_P (operands[0]))
                    790:     {
                    791:       if (FP_REG_P (operands[1]))
                    792:        return "fmov.dd %1,%0";
                    793:       if (GET_CODE (operands[1]) == REG)
                    794:        {
                    795:          output_asm_insn ("ixfr %1,%0", operands);
                    796:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    797:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    798:          return "ixfr %1,%0";
                    799:        }
                    800:       if (operands[1] == dconst0_rtx)
                    801:        return "fmov.dd f0,%0";
                    802:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
                    803:        {
                    804:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    805:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    806:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                    807:            output_asm_insn ("orh ha%%%m1,r0,r31", operands);
                    808:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    809:          cc_status.mdep = XEXP (operands[1], 0);
                    810:          return "fld.d l%%%m1(r31),%0";
                    811:        }
                    812:       return "fld.d %1,%0";
                    813:     }
                    814:   else if (FP_REG_P (operands[1]))
                    815:     {
                    816:       if (GET_CODE (operands[0]) == REG)
                    817:        {
                    818:          output_asm_insn ("fxfr %1,%0", operands);
                    819:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    820:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    821:          return "fxfr %1,%0";
                    822:        }
                    823:       if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
                    824:        {
                    825:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    826:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    827:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
                    828:            output_asm_insn ("orh ha%%%m0,r0,r31", operands);
                    829:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    830:          cc_status.mdep = XEXP (operands[0], 0);
                    831:          return "fst.d %1,l%%%m0(r31)";
                    832:        }
                    833:       return "fst.d %1,%0";
                    834:     }
                    835:   else abort ();
                    836: }
                    837: 
                    838: /* Return a REG that occurs in ADDR with coefficient 1.
                    839:    ADDR can be effectively incremented by incrementing REG.  */
                    840: 
                    841: static rtx
                    842: find_addr_reg (addr)
                    843:      rtx addr;
                    844: {
                    845:   while (GET_CODE (addr) == PLUS)
                    846:     {
                    847:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    848:        addr = XEXP (addr, 0);
                    849:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                    850:        addr = XEXP (addr, 1);
                    851:       else if (CONSTANT_P (XEXP (addr, 0)))
                    852:        addr = XEXP (addr, 1);
                    853:       else if (CONSTANT_P (XEXP (addr, 1)))
                    854:        addr = XEXP (addr, 0);
                    855:       else
                    856:        abort ();
                    857:     }
                    858:   if (GET_CODE (addr) == REG)
                    859:     return addr;
                    860:   abort ();
                    861: }
                    862: 
                    863: /* Return a template for a load instruction with mode MODE and
                    864:    arguments from the string ARGS.
                    865: 
                    866:    This string is in static storage.   */
                    867: 
                    868: static char *
                    869: load_opcode (mode, args, reg)
                    870:      enum machine_mode mode;
                    871:      char *args;
                    872:      rtx reg;
                    873: {
                    874:   static char buf[30];
                    875:   char *opcode;
                    876: 
                    877:   switch (mode)
                    878:     {
                    879:     case QImode:
                    880:       opcode = "ld.b";
                    881:       break;
                    882: 
                    883:     case HImode:
                    884:       opcode = "ld.s";
                    885:       break;
                    886: 
                    887:     case SImode:
                    888:     case SFmode:
                    889:       if (FP_REG_P (reg))
                    890:        opcode = "fld.l";
                    891:       else
                    892:        opcode = "ld.l";
                    893:       break;
                    894: 
1.1.1.2   root      895:     case DImode:
                    896:       if (!FP_REG_P (reg))
                    897:        abort ();
1.1       root      898:     case DFmode:
                    899:       opcode = "fld.d";
                    900:       break;
                    901: 
                    902:     default:
                    903:       abort ();
                    904:     }
                    905: 
                    906:   sprintf (buf, "%s %s", opcode, args);
                    907:   return buf;
                    908: }
                    909: 
                    910: /* Return a template for a store instruction with mode MODE and
                    911:    arguments from the string ARGS.
                    912: 
                    913:    This string is in static storage.   */
                    914: 
                    915: static char *
                    916: store_opcode (mode, args, reg)
                    917:      enum machine_mode mode;
                    918:      char *args;
                    919:      rtx reg;
                    920: {
                    921:   static char buf[30];
                    922:   char *opcode;
                    923: 
                    924:   switch (mode)
                    925:     {
                    926:     case QImode:
                    927:       opcode = "st.b";
                    928:       break;
                    929: 
                    930:     case HImode:
                    931:       opcode = "st.s";
                    932:       break;
                    933: 
                    934:     case SImode:
                    935:     case SFmode:
                    936:       if (FP_REG_P (reg))
                    937:        opcode = "fst.l";
                    938:       else
                    939:        opcode = "st.l";
                    940:       break;
                    941: 
1.1.1.2   root      942:     case DImode:
                    943:       if (!FP_REG_P (reg))
                    944:        abort ();
1.1       root      945:     case DFmode:
                    946:       opcode = "fst.d";
                    947:       break;
                    948: 
                    949:     default:
                    950:       abort ();
                    951:     }
                    952: 
                    953:   sprintf (buf, "%s %s", opcode, args);
                    954:   return buf;
                    955: }
                    956: 
                    957: /* Output a store-in-memory whose operands are OPERANDS[0,1].
                    958:    OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
                    959: 
                    960:    This function returns a template for an insn.
                    961:    This is in static storage.
                    962: 
                    963:    It may also output some insns directly.
                    964:    It may alter the values of operands[0] and operands[1].  */
                    965: 
                    966: char *
                    967: output_store (operands)
                    968:      rtx *operands;
                    969: {
                    970:   enum machine_mode mode = GET_MODE (operands[0]);
                    971:   rtx address = XEXP (operands[0], 0);
                    972:   char *string;
                    973: 
                    974:   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                    975:   cc_status.mdep = address;
                    976: 
                    977:   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                    978:         && (cc_prev_status.flags & CC_HI_R31_ADJ)
                    979:         && address == cc_prev_status.mdep))
                    980:     {
                    981:       output_asm_insn ("orh ha%%%m0,r0,r31", operands);
                    982:       cc_prev_status.mdep = address;
                    983:     }
                    984: 
                    985:   /* Store zero in two parts when appropriate.  */
                    986:   if (mode == DFmode && operands[1] == dconst0_rtx)
                    987:     return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);
                    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[1]))
                    993:     return output_move_double (operands);
                    994: 
                    995:   return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);
                    996: }
                    997: 
                    998: /* Output a load-from-memory whose operands are OPERANDS[0,1].
                    999:    OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
                   1000: 
                   1001:    This function returns a template for an insn.
                   1002:    This is in static storage.
                   1003: 
                   1004:    It may also output some insns directly.
                   1005:    It may alter the values of operands[0] and operands[1].  */
                   1006: 
                   1007: char *
                   1008: output_load (operands)
                   1009:      rtx *operands;
                   1010: {
                   1011:   enum machine_mode mode = GET_MODE (operands[0]);
                   1012:   rtx address = XEXP (operands[1], 0);
                   1013: 
                   1014:   /* We don't bother trying to see if we know %hi(address).
                   1015:      This is because we are doing a load, and if we know the
                   1016:      %hi value, we probably also know that value in memory.  */
                   1017:   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
                   1018:   cc_status.mdep = address;
                   1019: 
                   1020:   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                   1021:         && (cc_prev_status.flags & CC_HI_R31_ADJ)
                   1022:         && address == cc_prev_status.mdep
                   1023:         && cc_prev_status.mdep == cc_status.mdep))
                   1024:     {
                   1025:       output_asm_insn ("orh ha%%%m1,r0,r31", operands);
                   1026:       cc_prev_status.mdep = address;
                   1027:     }
                   1028: 
                   1029:   /* Code below isn't smart enough to move a doubleword in two parts,
                   1030:      so use output_move_double to do that in the cases that require it.  */
                   1031:   if ((mode == DImode || mode == DFmode)
                   1032:       && ! FP_REG_P (operands[0]))
                   1033:     return output_move_double (operands);
                   1034: 
                   1035:   return load_opcode (mode, "l%%%m1(r31),%0", operands[0]);
                   1036: }
                   1037: 
1.1.1.4 ! root     1038: #if 0
1.1       root     1039: /* Load the address specified by OPERANDS[3] into the register
                   1040:    specified by OPERANDS[0].
                   1041: 
                   1042:    OPERANDS[3] may be the result of a sum, hence it could either be:
                   1043: 
                   1044:    (1) CONST
                   1045:    (2) REG
                   1046:    (2) REG + CONST_INT
                   1047:    (3) REG + REG + CONST_INT
                   1048:    (4) REG + REG  (special case of 3).
                   1049: 
                   1050:    Note that (3) is not a legitimate address.
                   1051:    All cases are handled here.  */
                   1052: 
                   1053: void
                   1054: output_load_address (operands)
                   1055:      rtx *operands;
                   1056: {
                   1057:   rtx base, offset;
                   1058: 
                   1059:   if (CONSTANT_P (operands[3]))
                   1060:     {
                   1061:       output_asm_insn ("mov %3,%0", operands);
                   1062:       return;
                   1063:     }
                   1064: 
                   1065:   if (REG_P (operands[3]))
                   1066:     {
                   1067:       if (REGNO (operands[0]) != REGNO (operands[3]))
                   1068:        output_asm_insn ("mov %3,%0", operands);
                   1069:       return;
                   1070:     }
                   1071: 
                   1072:   if (GET_CODE (operands[3]) != PLUS)
                   1073:     abort ();
                   1074: 
                   1075:   base = XEXP (operands[3], 0);
                   1076:   offset = XEXP (operands[3], 1);
                   1077: 
                   1078:   if (GET_CODE (base) == CONST_INT)
                   1079:     {
                   1080:       rtx tmp = base;
                   1081:       base = offset;
                   1082:       offset = tmp;
                   1083:     }
                   1084: 
                   1085:   if (GET_CODE (offset) != CONST_INT)
                   1086:     {
                   1087:       /* Operand is (PLUS (REG) (REG)).  */
                   1088:       base = operands[3];
                   1089:       offset = const0_rtx;
                   1090:     }
                   1091: 
                   1092:   if (REG_P (base))
                   1093:     {
                   1094:       operands[6] = base;
                   1095:       operands[7] = offset;
                   1096:       if (SMALL_INT (offset))
                   1097:        output_asm_insn ("adds %7,%6,%0", operands);
                   1098:       else
                   1099:        output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
                   1100:     }
                   1101:   else if (GET_CODE (base) == PLUS)
                   1102:     {
                   1103:       operands[6] = XEXP (base, 0);
                   1104:       operands[7] = XEXP (base, 1);
                   1105:       operands[8] = offset;
                   1106: 
                   1107:       if (SMALL_INT (offset))
                   1108:        output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
                   1109:       else
                   1110:        output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
                   1111:     }
                   1112:   else
                   1113:     abort ();
                   1114: }
1.1.1.4 ! root     1115: #endif
1.1       root     1116: 
1.1.1.3   root     1117: /* Output code to place a size count SIZE in register REG.  */
1.1       root     1118: 
                   1119: static void
                   1120: output_size_for_block_move (size, reg, align)
                   1121:      rtx size, reg, align;
                   1122: {
                   1123:   rtx xoperands[3];
                   1124: 
                   1125:   xoperands[0] = reg;
                   1126:   xoperands[1] = size;
                   1127:   xoperands[2] = align;
                   1128: 
                   1129: #if 1
                   1130:   cc_status.flags &= ~ CC_KNOW_HI_R31;
                   1131:   output_asm_insn ("mov %1,%0", xoperands);
                   1132: #else
                   1133:   if (GET_CODE (size) == REG)
                   1134:     output_asm_insn ("sub %2,%1,%0", xoperands);
                   1135:   else
                   1136:     {
                   1137:       xoperands[1]
                   1138:        = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
                   1139:       cc_status.flags &= ~ CC_KNOW_HI_R31;
                   1140:       output_asm_insn ("mov %1,%0", xoperands);
                   1141:     }
                   1142: #endif
                   1143: }
                   1144: 
                   1145: /* Emit code to perform a block move.
                   1146: 
                   1147:    OPERANDS[0] is the destination.
                   1148:    OPERANDS[1] is the source.
                   1149:    OPERANDS[2] is the size.
                   1150:    OPERANDS[3] is the known safe alignment.
                   1151:    OPERANDS[4..6] are pseudos we can safely clobber as temps.  */
                   1152: 
                   1153: char *
                   1154: output_block_move (operands)
                   1155:      rtx *operands;
                   1156: {
                   1157:   /* A vector for our computed operands.  Note that load_output_address
                   1158:      makes use of (and can clobber) up to the 8th element of this vector.  */
                   1159:   rtx xoperands[10];
                   1160:   rtx zoperands[10];
                   1161:   static int movstrsi_label = 0;
                   1162:   int i, j;
                   1163:   rtx temp1 = operands[4];
                   1164:   rtx alignrtx = operands[3];
                   1165:   int align = INTVAL (alignrtx);
                   1166: 
                   1167:   xoperands[0] = operands[0];
                   1168:   xoperands[1] = operands[1];
                   1169:   xoperands[2] = temp1;
                   1170: 
                   1171:   /* We can't move more than four bytes at a time
                   1172:      because we have only one register to move them through.  */
                   1173:   if (align > 4)
                   1174:     {
                   1175:       align = 4;
                   1176:       alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
                   1177:     }
                   1178: 
                   1179:   /* Since we clobber untold things, nix the condition codes.  */
                   1180:   CC_STATUS_INIT;
                   1181: 
                   1182:   /* Recognize special cases of block moves.  These occur
                   1183:      when GNU C++ is forced to treat something as BLKmode
                   1184:      to keep it in memory, when its mode could be represented
                   1185:      with something smaller.
                   1186: 
                   1187:      We cannot do this for global variables, since we don't know
                   1188:      what pages they don't cross.  Sigh.  */
                   1189:   if (GET_CODE (operands[2]) == CONST_INT
                   1190:       && INTVAL (operands[2]) <= 16
                   1191:       && ! CONSTANT_ADDRESS_P (operands[0])
                   1192:       && ! CONSTANT_ADDRESS_P (operands[1]))
                   1193:     {
                   1194:       int size = INTVAL (operands[2]);
                   1195:       rtx op0 = xoperands[0];
                   1196:       rtx op1 = xoperands[1];
                   1197: 
                   1198:       cc_status.flags &= ~CC_KNOW_HI_R31;
                   1199:       if (align == 1)
                   1200:        {
                   1201:          if (memory_address_p (QImode, plus_constant (op0, size))
                   1202:              && memory_address_p (QImode, plus_constant (op1, size)))
                   1203:            {
                   1204:              for (i = size-1; i >= 0; i--)
                   1205:                {
                   1206:                  xoperands[0] = plus_constant (op0, i);
                   1207:                  xoperands[1] = plus_constant (op1, i);
                   1208:                  output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
                   1209:                                   xoperands);
                   1210:                }
                   1211:              return "";
                   1212:            }
                   1213:        }
                   1214:       else if (align == 2)
                   1215:        {
                   1216:          if (memory_address_p (HImode, plus_constant (op0, size))
                   1217:              && memory_address_p (HImode, plus_constant (op1, size)))
                   1218:            {
                   1219:              for (i = (size>>1)-1; i >= 0; i--)
                   1220:                {
                   1221:                  xoperands[0] = plus_constant (op0, i * 2);
                   1222:                  xoperands[1] = plus_constant (op1, i * 2);
                   1223:                  output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
                   1224:                                   xoperands);
                   1225:                }
                   1226:              return "";
                   1227:            }
                   1228:        }
                   1229:       else
                   1230:        {
                   1231:          if (memory_address_p (SImode, plus_constant (op0, size))
                   1232:              && memory_address_p (SImode, plus_constant (op1, size)))
                   1233:            {
                   1234:              for (i = (size>>2)-1; i >= 0; i--)
                   1235:                {
                   1236:                  xoperands[0] = plus_constant (op0, i * 4);
                   1237:                  xoperands[1] = plus_constant (op1, i * 4);
                   1238:                  output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
                   1239:                                   xoperands);
                   1240:                }
                   1241:              return "";
                   1242:            }
                   1243:        }
                   1244:     }
                   1245: 
                   1246:   /* This is the size of the transfer.
                   1247:      Either use the register which already contains the size,
                   1248:      or use a free register (used by no operands).  */
                   1249:   output_size_for_block_move (operands[2], operands[4], alignrtx);
                   1250: 
                   1251: #if 0
                   1252:   /* Also emit code to decrement the size value by ALIGN.  */
                   1253:   zoperands[0] = operands[0];
                   1254:   zoperands[3] = plus_constant (operands[0], align);
                   1255:   output_load_address (zoperands);
                   1256: #endif
                   1257: 
                   1258:   /* Generate number for unique label.  */
                   1259: 
                   1260:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1261: 
                   1262:   /* Copy the increment (negative) to a register for bla insn.  */
                   1263: 
                   1264:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
                   1265:   xoperands[5] = operands[5];
                   1266:   output_asm_insn ("mov %4,%5", xoperands);
                   1267: 
1.1.1.3   root     1268:   /* Make available a register which is a temporary.  */
                   1269: 
1.1       root     1270:   xoperands[6] = operands[6];
                   1271: 
                   1272:   /* Now the actual loop.
                   1273:      In xoperands, elements 1 and 0 are the input and output vectors.
                   1274:      Element 2 is the loop index.  Element 5 is the increment.  */
                   1275: 
                   1276:   if (align == 1)
                   1277:     {
                   1278:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3   root     1279:       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
                   1280: 
                   1281:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1282: 
                   1283:       output_asm_insn ("adds %1,%2,%1", xoperands);
                   1284:       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
                   1285:       output_asm_insn ("ld.b 0(%1),r31", xoperands);
                   1286:       output_asm_insn ("adds %5,%1,%1", xoperands);
1.1       root     1287:       output_asm_insn ("st.b r31,0(%6)", xoperands);
1.1.1.3   root     1288:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
                   1289:       output_asm_insn ("adds %5,%6,%6", xoperands);
1.1       root     1290:     }
                   1291:   if (align == 2)
                   1292:     {
                   1293:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3   root     1294:       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
                   1295: 
                   1296:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1297: 
                   1298:       output_asm_insn ("adds %1,%2,%1", xoperands);
                   1299:       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
                   1300:       output_asm_insn ("ld.s 0(%1),r31", xoperands);
                   1301:       output_asm_insn ("adds %5,%1,%1", xoperands);
1.1       root     1302:       output_asm_insn ("st.s r31,0(%6)", xoperands);
1.1.1.3   root     1303:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
                   1304:       output_asm_insn ("adds %5,%6,%6", xoperands);
1.1       root     1305:     }
                   1306:   if (align == 4)
                   1307:     {
                   1308:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3   root     1309:       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
                   1310: 
                   1311:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1312: 
                   1313:       output_asm_insn ("adds %1,%2,%1", xoperands);
                   1314:       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
                   1315:       output_asm_insn ("ld.l 0(%1),r31", xoperands);
                   1316:       output_asm_insn ("adds %5,%1,%1", xoperands);
1.1       root     1317:       output_asm_insn ("st.l r31,0(%6)", xoperands);
1.1.1.3   root     1318:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
                   1319:       output_asm_insn ("adds %5,%6,%6", xoperands);
1.1       root     1320:     }
                   1321: 
                   1322:   return "";
                   1323: }
                   1324: 
                   1325: /* Output a delayed branch insn with the delay insn in its
                   1326:    branch slot.  The delayed branch insn template is in TEMPLATE,
                   1327:    with operands OPERANDS.  The insn in its delay slot is INSN.
                   1328: 
                   1329:    As a special case, since we know that all memory transfers are via
                   1330:    ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
                   1331:    reference around the branch as
                   1332: 
                   1333:        orh ha%x,r0,r31
                   1334:        b ...
                   1335:        ld/st l%x(r31),...
                   1336: 
                   1337:    As another special case, we handle loading (SYMBOL_REF ...) and
                   1338:    other large constants around branches as well:
                   1339: 
                   1340:        orh h%x,r0,%0
                   1341:        b ...
                   1342:        or l%x,%0,%1
                   1343: 
                   1344:    */
                   1345: 
                   1346: char *
                   1347: output_delayed_branch (template, operands, insn)
                   1348:      char *template;
                   1349:      rtx *operands;
                   1350:      rtx insn;
                   1351: {
                   1352:   extern rtx recog_operand[];
                   1353:   rtx src = XVECEXP (PATTERN (insn), 0, 1);
                   1354:   rtx dest = XVECEXP (PATTERN (insn), 0, 0);
                   1355: 
                   1356:   if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
                   1357:       || (GET_CODE (src) == CONST_INT
1.1.1.3   root     1358:          && !(SMALL_INT (src) || (INTVAL (src) & 0xffff) == 0)))
1.1       root     1359:     {
                   1360:       rtx xoperands[2];
                   1361:       xoperands[0] = dest;
                   1362:       xoperands[1] = src;
                   1363: 
                   1364:       /* Output the `orh' insn.  */
                   1365:       output_asm_insn ("orh h%%%1,r0,%0", xoperands);
                   1366: 
                   1367:       /* Output the branch instruction next.  */
                   1368:       output_asm_insn (template, operands);
                   1369: 
                   1370:       /* Now output the `or' insn.  */
                   1371:       output_asm_insn ("or l%%%1,%0,%0", xoperands);
                   1372:     }
                   1373:   else if ((GET_CODE (src) == MEM
                   1374:            && CONSTANT_ADDRESS_P (XEXP (src, 0)))
                   1375:           || (GET_CODE (dest) == MEM
                   1376:               && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
                   1377:     {
                   1378:       rtx xoperands[2];
                   1379:       char *split_template;
                   1380:       xoperands[0] = dest;
                   1381:       xoperands[1] = src;
                   1382: 
                   1383:       /* Output the `orh' insn.  */
                   1384:       if (GET_CODE (src) == MEM)
                   1385:        {
                   1386:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                   1387:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                   1388:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                   1389:            output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
                   1390:          split_template = load_opcode (GET_MODE (dest),
1.1.1.3   root     1391:                                        "l%%%m1(r31),%0", dest);
1.1       root     1392:        }
                   1393:       else
                   1394:        {
                   1395:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                   1396:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                   1397:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
                   1398:            output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
                   1399:          split_template = store_opcode (GET_MODE (dest),
                   1400:                                         "%r1,l%%%m0(r31)", src);
                   1401:        }
                   1402: 
                   1403:       /* Output the branch instruction next.  */
                   1404:       output_asm_insn (template, operands);
                   1405: 
                   1406:       /* Now output the load or store.
                   1407:         No need to do a CC_STATUS_INIT, because we are branching anyway.  */
                   1408:       output_asm_insn (split_template, xoperands);
                   1409:     }
                   1410:   else
                   1411:     {
                   1412:       extern char *insn_template[];
                   1413:       extern char *(*insn_outfun[])();
                   1414:       extern int insn_n_operands[];
                   1415:       extern rtx alter_subreg();
                   1416:       int insn_code_number;
                   1417:       rtx pat = gen_rtx (SET, VOIDmode, dest, src);
                   1418:       rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
                   1419:       int i;
                   1420: 
                   1421:       /* Output the branch instruction first.  */
                   1422:       output_asm_insn (template, operands);
                   1423: 
                   1424:       /* Now recognize the insn which we put in its delay slot.
                   1425:         We must do this after outputing the branch insn,
                   1426:         since operands may just be a pointer to `recog_operand'.  */
                   1427:       insn_code_number = recog (pat, delay_insn);
                   1428:       if (insn_code_number == -1)
                   1429:        abort ();
                   1430: 
                   1431:       for (i = 0; i < insn_n_operands[insn_code_number]; i++)
                   1432:        {
                   1433:          if (GET_CODE (recog_operand[i]) == SUBREG)
                   1434:            recog_operand[i] = alter_subreg (recog_operand[i]);
                   1435:        }
                   1436: 
                   1437:       /* Now get the template for what this insn would
                   1438:         have been, without the branch.  Its operands are
                   1439:         exactly the same as they would be, so we don't
                   1440:         need to do an insn_extract.  */
                   1441:       template = insn_template[insn_code_number];
                   1442:       if (template == 0)
                   1443:        template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
                   1444:       output_asm_insn (template, recog_operand);
                   1445:     }
                   1446:   CC_STATUS_INIT;
                   1447:   return "";
                   1448: }
                   1449: 
                   1450: /* Output a newly constructed insn DELAY_INSN.  */
                   1451: char *
                   1452: output_delay_insn (delay_insn)
                   1453:      rtx delay_insn;
                   1454: {
                   1455:   char *template;
                   1456:   extern rtx recog_operand[];
                   1457:   extern char call_used_regs[];
                   1458:   extern char *insn_template[];
                   1459:   extern int insn_n_operands[];
                   1460:   extern char *(*insn_outfun[])();
                   1461:   extern rtx alter_subreg();
                   1462:   int insn_code_number;
                   1463:   extern int insn_n_operands[];
                   1464:   int i;
                   1465: 
                   1466:   /* Now recognize the insn which we put in its delay slot.
                   1467:      We must do this after outputing the branch insn,
                   1468:      since operands may just be a pointer to `recog_operand'.  */
                   1469:   insn_code_number = recog_memoized (delay_insn);
                   1470:   if (insn_code_number == -1)
                   1471:     abort ();
                   1472: 
                   1473:   /* Extract the operands of this delay insn.  */
                   1474:   INSN_CODE (delay_insn) = insn_code_number;
                   1475:   insn_extract (delay_insn);
                   1476: 
                   1477:   /* It is possible that this insn has not been properly scaned by final
                   1478:      yet.  If this insn's operands don't appear in the peephole's
                   1479:      actual operands, then they won't be fixed up by final, so we
                   1480:      make sure they get fixed up here.  -- This is a kludge.  */
                   1481:   for (i = 0; i < insn_n_operands[insn_code_number]; i++)
                   1482:     {
                   1483:       if (GET_CODE (recog_operand[i]) == SUBREG)
                   1484:        recog_operand[i] = alter_subreg (recog_operand[i]);
                   1485:     }
                   1486: 
                   1487: #ifdef REGISTER_CONSTRAINTS
                   1488:   if (! constrain_operands (insn_code_number))
                   1489:     abort ();
                   1490: #endif
                   1491: 
                   1492:   cc_prev_status = cc_status;
                   1493: 
                   1494:   /* Update `cc_status' for this instruction.
                   1495:      The instruction's output routine may change it further.
                   1496:      If the output routine for a jump insn needs to depend
                   1497:      on the cc status, it should look at cc_prev_status.  */
                   1498: 
                   1499:   NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
                   1500: 
                   1501:   /* Now get the template for what this insn would
                   1502:      have been, without the branch.  */
                   1503: 
                   1504:   template = insn_template[insn_code_number];
                   1505:   if (template == 0)
                   1506:     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
                   1507:   output_asm_insn (template, recog_operand);
                   1508:   return "";
                   1509: }

unix.superglobalmegacorp.com

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