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

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
                    363:         insn; 'sethi'.  */
                    364:       if ((INTVAL (op) & 0x3ff) == 0)
                    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: 
                   1038: /* Load the address specified by OPERANDS[3] into the register
                   1039:    specified by OPERANDS[0].
                   1040: 
                   1041:    OPERANDS[3] may be the result of a sum, hence it could either be:
                   1042: 
                   1043:    (1) CONST
                   1044:    (2) REG
                   1045:    (2) REG + CONST_INT
                   1046:    (3) REG + REG + CONST_INT
                   1047:    (4) REG + REG  (special case of 3).
                   1048: 
                   1049:    Note that (3) is not a legitimate address.
                   1050:    All cases are handled here.  */
                   1051: 
                   1052: void
                   1053: output_load_address (operands)
                   1054:      rtx *operands;
                   1055: {
                   1056:   rtx base, offset;
                   1057: 
                   1058:   if (CONSTANT_P (operands[3]))
                   1059:     {
                   1060:       output_asm_insn ("mov %3,%0", operands);
                   1061:       return;
                   1062:     }
                   1063: 
                   1064:   if (REG_P (operands[3]))
                   1065:     {
                   1066:       if (REGNO (operands[0]) != REGNO (operands[3]))
                   1067:        output_asm_insn ("mov %3,%0", operands);
                   1068:       return;
                   1069:     }
                   1070: 
                   1071:   if (GET_CODE (operands[3]) != PLUS)
                   1072:     abort ();
                   1073: 
                   1074:   base = XEXP (operands[3], 0);
                   1075:   offset = XEXP (operands[3], 1);
                   1076: 
                   1077:   if (GET_CODE (base) == CONST_INT)
                   1078:     {
                   1079:       rtx tmp = base;
                   1080:       base = offset;
                   1081:       offset = tmp;
                   1082:     }
                   1083: 
                   1084:   if (GET_CODE (offset) != CONST_INT)
                   1085:     {
                   1086:       /* Operand is (PLUS (REG) (REG)).  */
                   1087:       base = operands[3];
                   1088:       offset = const0_rtx;
                   1089:     }
                   1090: 
                   1091:   if (REG_P (base))
                   1092:     {
                   1093:       operands[6] = base;
                   1094:       operands[7] = offset;
                   1095:       if (SMALL_INT (offset))
                   1096:        output_asm_insn ("adds %7,%6,%0", operands);
                   1097:       else
                   1098:        output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
                   1099:     }
                   1100:   else if (GET_CODE (base) == PLUS)
                   1101:     {
                   1102:       operands[6] = XEXP (base, 0);
                   1103:       operands[7] = XEXP (base, 1);
                   1104:       operands[8] = offset;
                   1105: 
                   1106:       if (SMALL_INT (offset))
                   1107:        output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
                   1108:       else
                   1109:        output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
                   1110:     }
                   1111:   else
                   1112:     abort ();
                   1113: }
                   1114: 
1.1.1.3 ! root     1115: /* Output code to place a size count SIZE in register REG.  */
1.1       root     1116: 
                   1117: static void
                   1118: output_size_for_block_move (size, reg, align)
                   1119:      rtx size, reg, align;
                   1120: {
                   1121:   rtx xoperands[3];
                   1122: 
                   1123:   xoperands[0] = reg;
                   1124:   xoperands[1] = size;
                   1125:   xoperands[2] = align;
                   1126: 
                   1127: #if 1
                   1128:   cc_status.flags &= ~ CC_KNOW_HI_R31;
                   1129:   output_asm_insn ("mov %1,%0", xoperands);
                   1130: #else
                   1131:   if (GET_CODE (size) == REG)
                   1132:     output_asm_insn ("sub %2,%1,%0", xoperands);
                   1133:   else
                   1134:     {
                   1135:       xoperands[1]
                   1136:        = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
                   1137:       cc_status.flags &= ~ CC_KNOW_HI_R31;
                   1138:       output_asm_insn ("mov %1,%0", xoperands);
                   1139:     }
                   1140: #endif
                   1141: }
                   1142: 
                   1143: /* Emit code to perform a block move.
                   1144: 
                   1145:    OPERANDS[0] is the destination.
                   1146:    OPERANDS[1] is the source.
                   1147:    OPERANDS[2] is the size.
                   1148:    OPERANDS[3] is the known safe alignment.
                   1149:    OPERANDS[4..6] are pseudos we can safely clobber as temps.  */
                   1150: 
                   1151: char *
                   1152: output_block_move (operands)
                   1153:      rtx *operands;
                   1154: {
                   1155:   /* A vector for our computed operands.  Note that load_output_address
                   1156:      makes use of (and can clobber) up to the 8th element of this vector.  */
                   1157:   rtx xoperands[10];
                   1158:   rtx zoperands[10];
                   1159:   static int movstrsi_label = 0;
                   1160:   int i, j;
                   1161:   rtx temp1 = operands[4];
                   1162:   rtx alignrtx = operands[3];
                   1163:   int align = INTVAL (alignrtx);
                   1164: 
                   1165:   xoperands[0] = operands[0];
                   1166:   xoperands[1] = operands[1];
                   1167:   xoperands[2] = temp1;
                   1168: 
                   1169:   /* We can't move more than four bytes at a time
                   1170:      because we have only one register to move them through.  */
                   1171:   if (align > 4)
                   1172:     {
                   1173:       align = 4;
                   1174:       alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
                   1175:     }
                   1176: 
                   1177:   /* Since we clobber untold things, nix the condition codes.  */
                   1178:   CC_STATUS_INIT;
                   1179: 
                   1180:   /* Recognize special cases of block moves.  These occur
                   1181:      when GNU C++ is forced to treat something as BLKmode
                   1182:      to keep it in memory, when its mode could be represented
                   1183:      with something smaller.
                   1184: 
                   1185:      We cannot do this for global variables, since we don't know
                   1186:      what pages they don't cross.  Sigh.  */
                   1187:   if (GET_CODE (operands[2]) == CONST_INT
                   1188:       && INTVAL (operands[2]) <= 16
                   1189:       && ! CONSTANT_ADDRESS_P (operands[0])
                   1190:       && ! CONSTANT_ADDRESS_P (operands[1]))
                   1191:     {
                   1192:       int size = INTVAL (operands[2]);
                   1193:       rtx op0 = xoperands[0];
                   1194:       rtx op1 = xoperands[1];
                   1195: 
                   1196:       cc_status.flags &= ~CC_KNOW_HI_R31;
                   1197:       if (align == 1)
                   1198:        {
                   1199:          if (memory_address_p (QImode, plus_constant (op0, size))
                   1200:              && memory_address_p (QImode, plus_constant (op1, size)))
                   1201:            {
                   1202:              for (i = size-1; i >= 0; i--)
                   1203:                {
                   1204:                  xoperands[0] = plus_constant (op0, i);
                   1205:                  xoperands[1] = plus_constant (op1, i);
                   1206:                  output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
                   1207:                                   xoperands);
                   1208:                }
                   1209:              return "";
                   1210:            }
                   1211:        }
                   1212:       else if (align == 2)
                   1213:        {
                   1214:          if (memory_address_p (HImode, plus_constant (op0, size))
                   1215:              && memory_address_p (HImode, plus_constant (op1, size)))
                   1216:            {
                   1217:              for (i = (size>>1)-1; i >= 0; i--)
                   1218:                {
                   1219:                  xoperands[0] = plus_constant (op0, i * 2);
                   1220:                  xoperands[1] = plus_constant (op1, i * 2);
                   1221:                  output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
                   1222:                                   xoperands);
                   1223:                }
                   1224:              return "";
                   1225:            }
                   1226:        }
                   1227:       else
                   1228:        {
                   1229:          if (memory_address_p (SImode, plus_constant (op0, size))
                   1230:              && memory_address_p (SImode, plus_constant (op1, size)))
                   1231:            {
                   1232:              for (i = (size>>2)-1; i >= 0; i--)
                   1233:                {
                   1234:                  xoperands[0] = plus_constant (op0, i * 4);
                   1235:                  xoperands[1] = plus_constant (op1, i * 4);
                   1236:                  output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
                   1237:                                   xoperands);
                   1238:                }
                   1239:              return "";
                   1240:            }
                   1241:        }
                   1242:     }
                   1243: 
                   1244:   /* This is the size of the transfer.
                   1245:      Either use the register which already contains the size,
                   1246:      or use a free register (used by no operands).  */
                   1247:   output_size_for_block_move (operands[2], operands[4], alignrtx);
                   1248: 
                   1249: #if 0
                   1250:   /* Also emit code to decrement the size value by ALIGN.  */
                   1251:   zoperands[0] = operands[0];
                   1252:   zoperands[3] = plus_constant (operands[0], align);
                   1253:   output_load_address (zoperands);
                   1254: #endif
                   1255: 
                   1256:   /* Generate number for unique label.  */
                   1257: 
                   1258:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1259: 
                   1260:   /* Copy the increment (negative) to a register for bla insn.  */
                   1261: 
                   1262:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
                   1263:   xoperands[5] = operands[5];
                   1264:   output_asm_insn ("mov %4,%5", xoperands);
                   1265: 
1.1.1.3 ! root     1266:   /* Make available a register which is a temporary.  */
        !          1267: 
1.1       root     1268:   xoperands[6] = operands[6];
                   1269: 
                   1270:   /* Now the actual loop.
                   1271:      In xoperands, elements 1 and 0 are the input and output vectors.
                   1272:      Element 2 is the loop index.  Element 5 is the increment.  */
                   1273: 
                   1274:   if (align == 1)
                   1275:     {
                   1276:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 ! root     1277:       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
        !          1278: 
        !          1279:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
        !          1280: 
        !          1281:       output_asm_insn ("adds %1,%2,%1", xoperands);
        !          1282:       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
        !          1283:       output_asm_insn ("ld.b 0(%1),r31", xoperands);
        !          1284:       output_asm_insn ("adds %5,%1,%1", xoperands);
1.1       root     1285:       output_asm_insn ("st.b r31,0(%6)", xoperands);
1.1.1.3 ! root     1286:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
        !          1287:       output_asm_insn ("adds %5,%6,%6", xoperands);
1.1       root     1288:     }
                   1289:   if (align == 2)
                   1290:     {
                   1291:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 ! root     1292:       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
        !          1293: 
        !          1294:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
        !          1295: 
        !          1296:       output_asm_insn ("adds %1,%2,%1", xoperands);
        !          1297:       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
        !          1298:       output_asm_insn ("ld.s 0(%1),r31", xoperands);
        !          1299:       output_asm_insn ("adds %5,%1,%1", xoperands);
1.1       root     1300:       output_asm_insn ("st.s r31,0(%6)", xoperands);
1.1.1.3 ! root     1301:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
        !          1302:       output_asm_insn ("adds %5,%6,%6", xoperands);
1.1       root     1303:     }
                   1304:   if (align == 4)
                   1305:     {
                   1306:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
1.1.1.3 ! root     1307:       output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands);
        !          1308: 
        !          1309:       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
        !          1310: 
        !          1311:       output_asm_insn ("adds %1,%2,%1", xoperands);
        !          1312:       output_asm_insn ("adds %5,%2,%2\n.Lm%3:",  xoperands);
        !          1313:       output_asm_insn ("ld.l 0(%1),r31", xoperands);
        !          1314:       output_asm_insn ("adds %5,%1,%1", xoperands);
1.1       root     1315:       output_asm_insn ("st.l r31,0(%6)", xoperands);
1.1.1.3 ! root     1316:       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
        !          1317:       output_asm_insn ("adds %5,%6,%6", xoperands);
1.1       root     1318:     }
                   1319: 
                   1320:   return "";
                   1321: }
                   1322: 
                   1323: /* Output a delayed branch insn with the delay insn in its
                   1324:    branch slot.  The delayed branch insn template is in TEMPLATE,
                   1325:    with operands OPERANDS.  The insn in its delay slot is INSN.
                   1326: 
                   1327:    As a special case, since we know that all memory transfers are via
                   1328:    ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
                   1329:    reference around the branch as
                   1330: 
                   1331:        orh ha%x,r0,r31
                   1332:        b ...
                   1333:        ld/st l%x(r31),...
                   1334: 
                   1335:    As another special case, we handle loading (SYMBOL_REF ...) and
                   1336:    other large constants around branches as well:
                   1337: 
                   1338:        orh h%x,r0,%0
                   1339:        b ...
                   1340:        or l%x,%0,%1
                   1341: 
                   1342:    */
                   1343: 
                   1344: char *
                   1345: output_delayed_branch (template, operands, insn)
                   1346:      char *template;
                   1347:      rtx *operands;
                   1348:      rtx insn;
                   1349: {
                   1350:   extern rtx recog_operand[];
                   1351:   rtx src = XVECEXP (PATTERN (insn), 0, 1);
                   1352:   rtx dest = XVECEXP (PATTERN (insn), 0, 0);
                   1353: 
                   1354:   if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
                   1355:       || (GET_CODE (src) == CONST_INT
1.1.1.3 ! root     1356:          && !(SMALL_INT (src) || (INTVAL (src) & 0xffff) == 0)))
1.1       root     1357:     {
                   1358:       rtx xoperands[2];
                   1359:       xoperands[0] = dest;
                   1360:       xoperands[1] = src;
                   1361: 
                   1362:       /* Output the `orh' insn.  */
                   1363:       output_asm_insn ("orh h%%%1,r0,%0", xoperands);
                   1364: 
                   1365:       /* Output the branch instruction next.  */
                   1366:       output_asm_insn (template, operands);
                   1367: 
                   1368:       /* Now output the `or' insn.  */
                   1369:       output_asm_insn ("or l%%%1,%0,%0", xoperands);
                   1370:     }
                   1371:   else if ((GET_CODE (src) == MEM
                   1372:            && CONSTANT_ADDRESS_P (XEXP (src, 0)))
                   1373:           || (GET_CODE (dest) == MEM
                   1374:               && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
                   1375:     {
                   1376:       rtx xoperands[2];
                   1377:       char *split_template;
                   1378:       xoperands[0] = dest;
                   1379:       xoperands[1] = src;
                   1380: 
                   1381:       /* Output the `orh' insn.  */
                   1382:       if (GET_CODE (src) == MEM)
                   1383:        {
                   1384:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                   1385:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                   1386:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                   1387:            output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
                   1388:          split_template = load_opcode (GET_MODE (dest),
1.1.1.3 ! root     1389:                                        "l%%%m1(r31),%0", dest);
1.1       root     1390:        }
                   1391:       else
                   1392:        {
                   1393:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
                   1394:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
                   1395:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
                   1396:            output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
                   1397:          split_template = store_opcode (GET_MODE (dest),
                   1398:                                         "%r1,l%%%m0(r31)", src);
                   1399:        }
                   1400: 
                   1401:       /* Output the branch instruction next.  */
                   1402:       output_asm_insn (template, operands);
                   1403: 
                   1404:       /* Now output the load or store.
                   1405:         No need to do a CC_STATUS_INIT, because we are branching anyway.  */
                   1406:       output_asm_insn (split_template, xoperands);
                   1407:     }
                   1408:   else
                   1409:     {
                   1410:       extern char *insn_template[];
                   1411:       extern char *(*insn_outfun[])();
                   1412:       extern int insn_n_operands[];
                   1413:       extern rtx alter_subreg();
                   1414:       int insn_code_number;
                   1415:       rtx pat = gen_rtx (SET, VOIDmode, dest, src);
                   1416:       rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
                   1417:       int i;
                   1418: 
                   1419:       /* Output the branch instruction first.  */
                   1420:       output_asm_insn (template, operands);
                   1421: 
                   1422:       /* Now recognize the insn which we put in its delay slot.
                   1423:         We must do this after outputing the branch insn,
                   1424:         since operands may just be a pointer to `recog_operand'.  */
                   1425:       insn_code_number = recog (pat, delay_insn);
                   1426:       if (insn_code_number == -1)
                   1427:        abort ();
                   1428: 
                   1429:       for (i = 0; i < insn_n_operands[insn_code_number]; i++)
                   1430:        {
                   1431:          if (GET_CODE (recog_operand[i]) == SUBREG)
                   1432:            recog_operand[i] = alter_subreg (recog_operand[i]);
                   1433:        }
                   1434: 
                   1435:       /* Now get the template for what this insn would
                   1436:         have been, without the branch.  Its operands are
                   1437:         exactly the same as they would be, so we don't
                   1438:         need to do an insn_extract.  */
                   1439:       template = insn_template[insn_code_number];
                   1440:       if (template == 0)
                   1441:        template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
                   1442:       output_asm_insn (template, recog_operand);
                   1443:     }
                   1444:   CC_STATUS_INIT;
                   1445:   return "";
                   1446: }
                   1447: 
                   1448: /* Output a newly constructed insn DELAY_INSN.  */
                   1449: char *
                   1450: output_delay_insn (delay_insn)
                   1451:      rtx delay_insn;
                   1452: {
                   1453:   char *template;
                   1454:   extern rtx recog_operand[];
                   1455:   extern char call_used_regs[];
                   1456:   extern char *insn_template[];
                   1457:   extern int insn_n_operands[];
                   1458:   extern char *(*insn_outfun[])();
                   1459:   extern rtx alter_subreg();
                   1460:   int insn_code_number;
                   1461:   extern int insn_n_operands[];
                   1462:   int i;
                   1463: 
                   1464:   /* Now recognize the insn which we put in its delay slot.
                   1465:      We must do this after outputing the branch insn,
                   1466:      since operands may just be a pointer to `recog_operand'.  */
                   1467:   insn_code_number = recog_memoized (delay_insn);
                   1468:   if (insn_code_number == -1)
                   1469:     abort ();
                   1470: 
                   1471:   /* Extract the operands of this delay insn.  */
                   1472:   INSN_CODE (delay_insn) = insn_code_number;
                   1473:   insn_extract (delay_insn);
                   1474: 
                   1475:   /* It is possible that this insn has not been properly scaned by final
                   1476:      yet.  If this insn's operands don't appear in the peephole's
                   1477:      actual operands, then they won't be fixed up by final, so we
                   1478:      make sure they get fixed up here.  -- This is a kludge.  */
                   1479:   for (i = 0; i < insn_n_operands[insn_code_number]; i++)
                   1480:     {
                   1481:       if (GET_CODE (recog_operand[i]) == SUBREG)
                   1482:        recog_operand[i] = alter_subreg (recog_operand[i]);
                   1483:     }
                   1484: 
                   1485: #ifdef REGISTER_CONSTRAINTS
                   1486:   if (! constrain_operands (insn_code_number))
                   1487:     abort ();
                   1488: #endif
                   1489: 
                   1490:   cc_prev_status = cc_status;
                   1491: 
                   1492:   /* Update `cc_status' for this instruction.
                   1493:      The instruction's output routine may change it further.
                   1494:      If the output routine for a jump insn needs to depend
                   1495:      on the cc status, it should look at cc_prev_status.  */
                   1496: 
                   1497:   NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
                   1498: 
                   1499:   /* Now get the template for what this insn would
                   1500:      have been, without the branch.  */
                   1501: 
                   1502:   template = insn_template[insn_code_number];
                   1503:   if (template == 0)
                   1504:     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
                   1505:   output_asm_insn (template, recog_operand);
                   1506:   return "";
                   1507: }

unix.superglobalmegacorp.com

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