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

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

unix.superglobalmegacorp.com

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