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

1.1       root        1: /* Subroutines for insn-output.c for Sun SPARC.
1.1.1.9 ! root        2:    Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
1.1       root        3:    Contributed by Michael Tiemann ([email protected])
                      4: 
                      5: This file is part of GNU CC.
                      6: 
                      7: GNU CC is distributed in the hope that it will be useful,
                      8: but WITHOUT ANY WARRANTY.  No author or distributor
                      9: accepts responsibility to anyone for the consequences of using it
                     10: or for whether it serves any particular purpose or works at all,
                     11: unless he says so in writing.  Refer to the GNU CC General Public
                     12: License for full details.
                     13: 
                     14: Everyone is granted permission to copy, modify and redistribute
                     15: GNU CC, but only under the conditions described in the
                     16: GNU CC General Public License.   A copy of this license is
                     17: supposed to have been given to you along with GNU CC so you
                     18: can know your rights and responsibilities.  It should be in a
                     19: file named COPYING.  Among other things, the copyright notice
                     20: and this notice must be preserved on all copies.  */
                     21: 
                     22: /* Global variables for machine-dependend things.  */
                     23: 
                     24: /* This should go away if we pass floats to regs via
1.1.1.4   root       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!).  */
1.1       root       27: extern int frame_pointer_needed;
                     28: 
                     29: static rtx find_addr_reg ();
                     30: 
1.1.1.9 ! root       31: rtx next_real_insn_no_labels ();
        !            32: 
1.1.1.8   root       33: /* Return non-zero only if OP is a register of mode MODE,
                     34:    or const0_rtx.  */
                     35: int
                     36: reg_or_0_operand (op, mode)
1.1.1.7   root       37:      rtx op;
                     38:      enum machine_mode mode;
                     39: {
1.1.1.8   root       40:   return (op == const0_rtx || register_operand (op, mode));
1.1.1.7   root       41: }
                     42: 
1.1.1.9 ! root       43: /* Return non-zero if this pattern, can be evaluated safely, even if it
        !            44:    was not asked for.  */
        !            45: int
        !            46: safe_insn_src_p (op, mode)
        !            47:      rtx op;
        !            48:      enum machine_mode mode;
        !            49: {
        !            50:   /* Just experimenting.  */
        !            51: 
        !            52:   /* No floating point src is safe if it contains an arithmetic
        !            53:      operation, since that operation may trap.  */
        !            54:   switch (GET_CODE (op))
        !            55:     {
        !            56:     case CONST_INT:
        !            57:     case LABEL_REF:
        !            58:     case SYMBOL_REF:
        !            59:     case CONST:
        !            60:       return 1;
        !            61: 
        !            62:     case REG:
        !            63:       return 1;
        !            64: 
        !            65:     case MEM:
        !            66:       return CONSTANT_ADDRESS_P (XEXP (op, 0));
        !            67: 
        !            68:       /* We never need to negate or complement constants.  */
        !            69:     case NEG:
        !            70:       return (mode != SFmode && mode != DFmode);
        !            71:     case NOT:
        !            72:       return 1;
        !            73: 
        !            74:     case MINUS:
        !            75:     case PLUS:
        !            76:       return (mode != SFmode && mode != DFmode);
        !            77:     case AND:
        !            78:     case IOR:
        !            79:     case XOR:
        !            80:     case LSHIFT:
        !            81:     case ASHIFT:
        !            82:     case ASHIFTRT:
        !            83:     case LSHIFTRT:
        !            84:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
        !            85:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
        !            86:        return 0;
        !            87:       return 1;
        !            88: 
        !            89:     default:
        !            90:       return 0;
        !            91:     }
        !            92: }
        !            93: 
        !            94: /* Return 1 if REG is clobbered in IN.
        !            95:    Return 0 if REG is used in IN (other than being clobbered).
        !            96:    Return 2 if REG does not appear in IN.  */
        !            97: 
        !            98: static int
        !            99: reg_clobbered_p (reg, in)
        !           100:      rtx reg;
        !           101:      rtx in;
        !           102: {
        !           103:   register char *fmt;
        !           104:   register int i, result = 0;
        !           105: 
        !           106:   register enum rtx_code code;
        !           107: 
        !           108:   if (in == 0)
        !           109:     return 2;
        !           110: 
        !           111:   code = GET_CODE (in);
        !           112: 
        !           113:   switch (code)
        !           114:     {
        !           115:       /* Let these fail out quickly.  */
        !           116:     case CONST_INT:
        !           117:     case SYMBOL_REF:
        !           118:     case CONST:
        !           119:       return 2;
        !           120: 
        !           121:     case SUBREG:
        !           122:       if (SUBREG_WORD (in) != 0)
        !           123:        in = gen_rtx (REG, SImode, REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
        !           124:       else
        !           125:        in = SUBREG_REG (in);
        !           126: 
        !           127:     case REG:
        !           128:       if (in == reg
        !           129:          || refers_to_regno_p (REGNO (reg),
        !           130:                                REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           131:                                in, 0))
        !           132:        return 0;
        !           133:       return 2;
        !           134: 
        !           135:     case SET:
        !           136:       if (SET_SRC (in) == reg
        !           137:          || refers_to_regno_p (REGNO (reg),
        !           138:                                REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           139:                                SET_SRC (in), 0))
        !           140:        return 0;
        !           141: 
        !           142:       if (SET_DEST (in) == reg)
        !           143:        return 1;
        !           144: 
        !           145:       if (refers_to_regno_p (REGNO (reg),
        !           146:                             REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           147:                             SET_DEST (in), 0))
        !           148:        if (GET_CODE (SET_DEST (in)) == REG
        !           149:            || GET_CODE (SET_DEST (in)) == SUBREG)
        !           150:          return 1;
        !           151:        else
        !           152:          return 0;
        !           153:       return 2;
        !           154: 
        !           155:     case USE:
        !           156:       if (XEXP (in, 0) == reg
        !           157:          || refers_to_regno_p (REGNO (reg),
        !           158:                                REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           159:                                XEXP (in, 0), 0))
        !           160:        return 0;
        !           161:       return 2;
        !           162: 
        !           163:     case CLOBBER:
        !           164:       if (XEXP (in, 0) == reg)
        !           165:        return 1;
        !           166:       /* If the CLOBBER expression is a SUBREG, accept that as a
        !           167:         clobber.  But if it is some expression based on this register,
        !           168:         that is like a USE as far as this register is concerned,
        !           169:         so we won't take it.  */
        !           170:       if (refers_to_regno_p (REGNO (reg),
        !           171:                             REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           172:                             XEXP (in, 0), 0))
        !           173:        if (GET_CODE (XEXP (in, 0)) == REG
        !           174:            || GET_CODE (XEXP (in, 0)) == SUBREG)
        !           175:          return 1;
        !           176:        else
        !           177:          return 0;
        !           178:       return 2;
        !           179:     }
        !           180: 
        !           181:   fmt = GET_RTX_FORMAT (code);
        !           182: 
        !           183:   result = 2;
        !           184: 
        !           185:   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        !           186:     {
        !           187:       if (fmt[i] == 'E')
        !           188:        {
        !           189:          register int j;
        !           190:          for (j = XVECLEN (in, i) - 1; j >= 0; j--)
        !           191:            switch (reg_clobbered_p (reg, XVECEXP (in, i, j)))
        !           192:              {
        !           193:              case 0:
        !           194:                return 0;
        !           195:              case 2:
        !           196:                continue;
        !           197:              case 1:
        !           198:                result = 1;
        !           199:                break;
        !           200:              }
        !           201:        }
        !           202:       else if (fmt[i] == 'e')
        !           203:        switch (reg_clobbered_p (reg, XEXP (in, i)))
        !           204:          {
        !           205:          case 0:
        !           206:            return 0;
        !           207:          case 2:
        !           208:            continue;
        !           209:          case 1:
        !           210:            result = 1;
        !           211:            break;
        !           212:          }
        !           213:     }
        !           214:   return result;
        !           215: }
        !           216: 
        !           217: /* Return non-zero if OP can be written to without screwing up
        !           218:    GCC's model of what's going on.  It is assumed that this operand
        !           219:    appears in the dest position of a SET insn in a conditional
        !           220:    branch's delay slot.  AFTER is the label to start looking from.  */
        !           221: int
        !           222: operand_clobbered_before_used_after (op, after)
        !           223:      rtx op;
        !           224:      rtx after;
        !           225: {
        !           226:   extern char call_used_regs[];
        !           227: 
        !           228:   /* Just experimenting.  */
        !           229:   if (GET_CODE (op) == CC0)
        !           230:     return 1;
        !           231:   if (GET_CODE (op) == REG)
        !           232:     {
        !           233:       rtx insn;
        !           234: 
        !           235:       if (op == stack_pointer_rtx)
        !           236:        return 0;
        !           237: 
        !           238:       for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
        !           239:        {
        !           240:          if (GET_CODE (insn) == NOTE)
        !           241:            continue;
        !           242:          if (GET_CODE (insn) == INSN
        !           243:              || GET_CODE (insn) == JUMP_INSN
        !           244:              || GET_CODE (insn) == CALL_INSN)
        !           245:            {
        !           246:              switch (reg_clobbered_p (op, PATTERN (insn)))
        !           247:                {
        !           248:                case 0:
        !           249:                  return 0;
        !           250:                case 2:
        !           251:                  break;
        !           252:                case 1:
        !           253:                  return 1;
        !           254:                }
        !           255:              if (dead_or_set_p (insn, op))
        !           256:                return 1;
        !           257:            }
        !           258:          else if (GET_CODE (insn) == CODE_LABEL)
        !           259:            return 0;
        !           260:          if (GET_CODE (insn) == JUMP_INSN)
        !           261:            {
        !           262:              if (condjump_p (insn))
        !           263:                return 0;
        !           264:              /* This is a jump insn which has already
        !           265:                 been mangled.  We can't tell what it does.  */
        !           266:              if (GET_CODE (PATTERN (insn)) == PARALLEL)
        !           267:                return 0;
        !           268:              if (! JUMP_LABEL (insn))
        !           269:                return 0;
        !           270:              /* Keep following jumps.  */
        !           271:              insn = JUMP_LABEL (insn);
        !           272:            }
        !           273:        }
        !           274:       return 1;
        !           275:     }
        !           276: 
        !           277:   /* In both of these cases, the first insn executed
        !           278:      for this op will be a sethi %hi(whatever),%g1,
        !           279:      which is tolerable.  */
        !           280:   if (GET_CODE (op) == MEM)
        !           281:     return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
        !           282: 
        !           283:   return 0;
        !           284: }
        !           285: 
1.1.1.4   root      286: /* Return non-zero if this pattern, as a source to a "SET",
                    287:    is known to yield an instruction of unit size.  */
                    288: int
                    289: single_insn_src_p (op, mode)
                    290:      rtx op;
                    291:      enum machine_mode mode;
1.1       root      292: {
1.1.1.4   root      293:   switch (GET_CODE (op))
                    294:     {
                    295:     case CONST_INT:
1.1.1.9 ! root      296: #if 1
        !           297:       /* This is not always a single insn src, technically,
        !           298:         but output_delayed_branch knows how to deal with it.  */
        !           299:       return 1;
        !           300: #else
1.1.1.4   root      301:       if (SMALL_INT (op))
                    302:        return 1;
1.1.1.9 ! root      303:       /* We can put this set insn into delay slot, because this is one
        !           304:         insn; 'sethi'.  */
        !           305:       if ((INTVAL (op) & 0x3ff) == 0)
        !           306:        return 1;
        !           307: 
        !           308:       /* This is not a single insn src, technically,
        !           309:         but output_delayed_branch knows how to deal with it.  */
        !           310:       return 1;
        !           311: #endif
        !           312: 
        !           313: #if 1
        !           314:     case SYMBOL_REF:
        !           315:       /* This is not a single insn src, technically,
        !           316:         but output_delayed_branch knows how to deal with it.  */
        !           317:       return 1;
        !           318: #else
1.1.1.4   root      319:       return 0;
1.1.1.9 ! root      320: #endif
1.1.1.4   root      321: 
                    322:     case REG:
1.1.1.7   root      323:       return 1;
                    324: 
1.1.1.4   root      325:     case MEM:
1.1.1.8   root      326: #if 0
                    327:       /* This is not a single insn src, technically,
1.1.1.9 ! root      328:         but output_delayed_branch knows how to deal with it.  */
1.1.1.7   root      329:       if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF)
                    330:        return 0;
1.1.1.8   root      331: #endif
1.1.1.4   root      332:       return 1;
                    333: 
                    334:       /* We never need to negate or complement constants.  */
                    335:     case NEG:
1.1.1.9 ! root      336:       return (mode != DFmode);
        !           337:     case NOT:
1.1.1.4   root      338:       return 1;
                    339: 
                    340:     case MINUS:
1.1.1.9 ! root      341:       /* If the target is cc0, then these insns will take
        !           342:         two insns (one being a nop).  */
        !           343:       return (mode != SFmode && mode != DFmode);
        !           344:     case PLUS:
1.1.1.4   root      345:     case AND:
                    346:     case IOR:
                    347:     case XOR:
                    348:     case LSHIFT:
                    349:     case ASHIFT:
                    350:     case ASHIFTRT:
                    351:     case LSHIFTRT:
                    352:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
                    353:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
                    354:        return 0;
                    355:       return 1;
                    356: 
                    357:     case SUBREG:
                    358:       if (SUBREG_WORD (op) != 0)
                    359:        return 0;
                    360:       return single_insn_src_p (SUBREG_REG (op), mode);
                    361: 
                    362:     case SIGN_EXTEND:
                    363:     case ZERO_EXTEND:
1.1.1.9 ! root      364:       /* Lazy... could check for more cases.  */
        !           365:       if (GET_CODE (XEXP (op, 0)) == MEM
        !           366:          && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
        !           367:        return 1;
        !           368:       return 0;
        !           369: 
        !           370:       /* Not doing floating point, since they probably
        !           371:         take longer than the branch slot they might fill.  */
        !           372:     case FLOAT_EXTEND:
        !           373:     case FLOAT_TRUNCATE:
        !           374:     case FLOAT:
        !           375:     case FIX:
        !           376:     case UNSIGNED_FLOAT:
        !           377:     case UNSIGNED_FIX:
        !           378:       return 0;
        !           379: 
        !           380:     default:
        !           381:       return 0;
        !           382:     }
        !           383: }
        !           384: 
        !           385: /* Nonzero only if this *really* is a single insn operand.  */
        !           386: int
        !           387: strict_single_insn_op_p (op, mode)
        !           388:      rtx op;
        !           389:      enum machine_mode mode;
        !           390: {
        !           391:   if (mode == VOIDmode)
        !           392:     mode = GET_MODE (op);
        !           393: 
        !           394:   switch (GET_CODE (op))
        !           395:     {
        !           396:     case CC0:
        !           397:       return 1;
        !           398: 
        !           399:     case CONST_INT:
        !           400:       if (SMALL_INT (op))
        !           401:        return 1;
        !           402:       /* We can put this set insn into delay slot, because this is one
        !           403:         insn; 'sethi'.  */
        !           404:       if ((INTVAL (op) & 0x3ff) == 0)
        !           405:        return 1;
        !           406:       return 0;
        !           407: 
        !           408:     case SYMBOL_REF:
        !           409:       return 0;
        !           410: 
        !           411:     case REG:
        !           412:       return (mode != DFmode && mode != DImode);
        !           413: 
        !           414:     case MEM:
        !           415:       if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
        !           416:        return (mode != DFmode && mode != DImode);
        !           417:       return 0;
        !           418: 
        !           419:       /* We never need to negate or complement constants.  */
        !           420:     case NEG:
        !           421:       return (mode != DFmode);
        !           422:     case NOT:
        !           423:       return 1;
        !           424: 
        !           425:     case MINUS:
        !           426:       /* If the target is cc0, then these insns will take
        !           427:         two insns (one being a nop).  */
        !           428:       return (mode != SFmode && mode != DFmode);
        !           429:     case PLUS:
        !           430:     case AND:
        !           431:     case IOR:
        !           432:     case XOR:
        !           433:     case LSHIFT:
        !           434:     case ASHIFT:
        !           435:     case ASHIFTRT:
        !           436:     case LSHIFTRT:
        !           437:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
        !           438:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
        !           439:        return 0;
        !           440:       return 1;
        !           441: 
        !           442:     case SUBREG:
        !           443:       if (SUBREG_WORD (op) != 0)
        !           444:        return 0;
        !           445:       return strict_single_insn_op_p (SUBREG_REG (op), mode);
        !           446: 
        !           447:     case SIGN_EXTEND:
        !           448:     case ZERO_EXTEND:
        !           449:       if (GET_CODE (XEXP (op, 0)) == MEM
        !           450:          && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
        !           451:        return 1;
1.1.1.4   root      452:       return 0;
                    453: 
                    454:       /* Not doing floating point, since they probably
                    455:         take longer than the branch slot they might fill.  */
                    456:     case FLOAT_EXTEND:
                    457:     case FLOAT_TRUNCATE:
                    458:     case FLOAT:
                    459:     case FIX:
                    460:     case UNSIGNED_FLOAT:
                    461:     case UNSIGNED_FIX:
                    462:       return 0;
                    463: 
                    464:     default:
                    465:       return 0;
                    466:     }
1.1       root      467: }
1.1.1.4   root      468: 
1.1.1.9 ! root      469: /* Return truth value of whether OP is a relational operator.  */
        !           470: int
        !           471: relop (op, mode)
        !           472:      rtx op;
        !           473:      enum machine_mode mode;
        !           474: {
        !           475:   switch (GET_CODE (op))
        !           476:     {
        !           477:     case EQ:
        !           478:     case NE:
        !           479:     case GT:
        !           480:     case GE:
        !           481:     case LT:
        !           482:     case LE:
        !           483:     case GTU:
        !           484:     case GEU:
        !           485:     case LTU:
        !           486:     case LEU:
        !           487:       return 1;
        !           488:     }
        !           489:   return 0;
        !           490: }
        !           491: 
        !           492: /* Return truth value of wheterh OP is EQ or NE.  */
        !           493: int
        !           494: eq_or_neq (op, mode)
        !           495:      rtx op;
        !           496:      enum machine_mode mode;
        !           497: {
        !           498:   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
        !           499: }
        !           500: 
1.1.1.5   root      501: /* Return truth value of whether OP can be used as an operands in a three
                    502:    address arithmetic insn (such as add %o1,7,%l2) of mode MODE.  */
1.1       root      503: 
                    504: int
                    505: arith_operand (op, mode)
                    506:      rtx op;
                    507:      enum machine_mode mode;
                    508: {
                    509:   return (register_operand (op, mode)
                    510:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
                    511: }
                    512: 
1.1.1.5   root      513: /* Return truth value of whether OP can be used as an operand in a two
                    514:    address arithmetic insn (such as set 123456,%o4) of mode MODE.  */
1.1.1.4   root      515: 
1.1       root      516: int
                    517: arith32_operand (op, mode)
                    518:      rtx op;
                    519:      enum machine_mode mode;
                    520: {
                    521:   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
                    522: }
                    523: 
1.1.1.5   root      524: /* Return truth value of whether OP is a integer which fits the
                    525:    range constraining immediate operands in three-address insns.  */
                    526: 
1.1.1.3   root      527: int
                    528: small_int (op, mode)
                    529:      rtx op;
                    530:      enum machine_mode mode;
                    531: {
                    532:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
                    533: }
                    534: 
1.1       root      535: /* Return the best assembler insn template
                    536:    for moving operands[1] into operands[0] as a fullword.  */
                    537: 
                    538: static char *
                    539: singlemove_string (operands)
                    540:      rtx *operands;
                    541: {
                    542:   if (GET_CODE (operands[0]) == MEM)
1.1.1.8   root      543:     {
                    544:       if (GET_CODE (operands[1]) != MEM)
                    545:        if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
                    546:          {
                    547:            if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
                    548:                   && cc_prev_status.mdep == XEXP (operands[0], 0)))
                    549:              output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
                    550:            cc_status.flags |= CC_KNOW_HI_G1;
                    551:            cc_status.mdep = XEXP (operands[0], 0);
                    552:            return "st %1,[%%lo(%m0)+%%g1]";
                    553:          }
                    554:        else
                    555:          return "st %r1,%0";
                    556:       else
                    557:        {
                    558:          rtx xoperands[2];
                    559: 
                    560:          cc_status.flags &= ~CC_F0_IS_0;
                    561:          xoperands[0] = gen_rtx (REG, SFmode, 32);
                    562:          xoperands[1] = operands[1];
                    563:          output_asm_insn (singlemove_string (xoperands), xoperands);
                    564:          xoperands[1] = xoperands[0];
                    565:          xoperands[0] = operands[0];
                    566:          output_asm_insn (singlemove_string (xoperands), xoperands);
                    567:          return "";
                    568:        }
                    569:     }
1.1       root      570:   if (GET_CODE (operands[1]) == MEM)
1.1.1.8   root      571:     {
                    572:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
                    573:        {
                    574:          if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
                    575:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                    576:            output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
                    577:          cc_status.flags |= CC_KNOW_HI_G1;
                    578:          cc_status.mdep = XEXP (operands[1], 0);
                    579:          return "ld [%%lo(%m1)+%%g1],%0";
                    580:        }
                    581:       return "ld %1,%0";
                    582:     }
1.1.1.3   root      583:   return "mov %1,%0";
1.1       root      584: }
                    585: 
                    586: /* Output assembler code to perform a doubleword move insn
                    587:    with operands OPERANDS.  */
                    588: 
                    589: char *
                    590: output_move_double (operands)
                    591:      rtx *operands;
                    592: {
                    593:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    594:   rtx latehalf[2];
                    595:   rtx addreg0 = 0, addreg1 = 0;
                    596: 
                    597:   /* First classify both operands.  */
                    598: 
                    599:   if (REG_P (operands[0]))
                    600:     optype0 = REGOP;
                    601:   else if (offsetable_memref_p (operands[0]))
                    602:     optype0 = OFFSOP;
                    603:   else if (GET_CODE (operands[0]) == MEM)
                    604:     optype0 = MEMOP;
                    605:   else
                    606:     optype0 = RNDOP;
                    607: 
                    608:   if (REG_P (operands[1]))
                    609:     optype1 = REGOP;
                    610:   else if (CONSTANT_P (operands[1])
                    611:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    612:     optype1 = CNSTOP;
                    613:   else if (offsetable_memref_p (operands[1]))
                    614:     optype1 = OFFSOP;
                    615:   else if (GET_CODE (operands[1]) == MEM)
1.1.1.7   root      616:     optype1 = MEMOP;
1.1       root      617:   else
                    618:     optype1 = RNDOP;
                    619: 
                    620:   /* Check for the cases that the operand constraints are not
                    621:      supposed to allow to happen.  Abort if we get one,
                    622:      because generating code for these cases is painful.  */
                    623: 
                    624:   if (optype0 == RNDOP || optype1 == RNDOP)
                    625:     abort ();
                    626: 
                    627:   /* If an operand is an unoffsettable memory ref, find a register
                    628:      we can increment temporarily to make it refer to the second word.  */
                    629: 
                    630:   if (optype0 == MEMOP)
                    631:     addreg0 = find_addr_reg (operands[0]);
                    632: 
                    633:   if (optype1 == MEMOP)
                    634:     addreg1 = find_addr_reg (operands[1]);
                    635: 
                    636:   /* Ok, we can do one word at a time.
                    637:      Normally we do the low-numbered word first,
                    638:      but if either operand is autodecrementing then we
                    639:      do the high-numbered word first.
                    640: 
                    641:      In either case, set up in LATEHALF the operands to use
                    642:      for the high-numbered word and in some cases alter the
                    643:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    644: 
                    645:   if (optype0 == REGOP)
                    646:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    647:   else if (optype0 == OFFSOP)
                    648:     latehalf[0] = adj_offsetable_operand (operands[0], 4);
                    649:   else
                    650:     latehalf[0] = operands[0];
                    651: 
                    652:   if (optype1 == REGOP)
                    653:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    654:   else if (optype1 == OFFSOP)
                    655:     latehalf[1] = adj_offsetable_operand (operands[1], 4);
                    656:   else if (optype1 == CNSTOP)
                    657:     {
                    658:       if (CONSTANT_P (operands[1]))
                    659:        latehalf[1] = const0_rtx;
                    660:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    661:        {
1.1.1.9 ! root      662:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
        !           663:                                 CONST_DOUBLE_HIGH (operands[1]));
        !           664:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
        !           665:                                 CONST_DOUBLE_LOW (operands[1]));
1.1       root      666:        }
                    667:     }
                    668:   else
                    669:     latehalf[1] = operands[1];
                    670: 
                    671:   /* If the first move would clobber the source of the second one,
1.1.1.3   root      672:      do them in the other order.
                    673: 
                    674:      RMS says "This happens only for registers;
1.1       root      675:      such overlap can't happen in memory unless the user explicitly
1.1.1.3   root      676:      sets it up, and that is an undefined circumstance."
                    677: 
                    678:      but it happens on the sparc when loading parameter registers,
                    679:      so I am going to define that circumstance, and make it work
                    680:      as expected.  */
                    681: 
                    682:   /* Easy case: try moving both words at once.  */
1.1.1.8   root      683:   /* First check for moving between an even/odd register pair
                    684:      and a memory location.  */
                    685:   if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP
1.1.1.3   root      686:        && (REGNO (operands[0]) & 1) == 0)
1.1.1.8   root      687:       || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP
1.1.1.3   root      688:          && (REGNO (operands[1]) & 1) == 0))
                    689:     {
                    690:       rtx op1, op2;
                    691:       rtx base = 0, offset = const0_rtx;
1.1       root      692: 
1.1.1.8   root      693:       /* OP1 gets the register pair, and OP2 gets the memory address.  */
1.1.1.3   root      694:       if (optype0 == REGOP)
                    695:        op1 = operands[0], op2 = XEXP (operands[1], 0);
                    696:       else
                    697:        op1 = operands[1], op2 = XEXP (operands[0], 0);
                    698: 
1.1.1.8   root      699:       /* Now see if we can trust the address to be 8-byte aligned.  */
1.1.1.4   root      700:       /* Trust global variables.  */
1.1.1.8   root      701:       if (CONSTANT_ADDRESS_P (op2))
1.1.1.4   root      702:        {
1.1.1.8   root      703:          operands[0] = op1;
                    704:          operands[1] = op2;
                    705:          if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
                    706:                 && cc_prev_status.mdep == op2))
1.1.1.9 ! root      707:            output_asm_insn ("sethi %%hi(%1),%%g1", operands);
1.1.1.8   root      708:          cc_status.flags |= CC_KNOW_HI_G1;
                    709:          cc_status.mdep = op2;
1.1.1.4   root      710:          if (op1 == operands[0])
1.1.1.9 ! root      711:            return "ldd [%%lo(%1)+%%g1],%0";
1.1.1.4   root      712:          else
1.1.1.9 ! root      713:            return "std [%%lo(%1)+%%g1],%0";
1.1.1.4   root      714:        }
1.1.1.3   root      715: 
1.1.1.4   root      716:       if (GET_CODE (op2) == PLUS)
                    717:        {
                    718:          if (GET_CODE (XEXP (op2, 0)) == REG)
                    719:            base = XEXP (op2, 0), offset = XEXP (op2, 1);
                    720:          else if (GET_CODE (XEXP (op2, 1)) == REG)
                    721:            base = XEXP (op2, 1), offset = XEXP (op2, 0);
                    722:        }
                    723: 
                    724:       /* Trust round enough offsets from the stack or frame pointer.  */
1.1.1.3   root      725:       if (base
1.1.1.4   root      726:          && (REGNO (base) == FRAME_POINTER_REGNUM
                    727:              || REGNO (base) == STACK_POINTER_REGNUM))
                    728:        {
                    729:          if (GET_CODE (offset) == CONST_INT
                    730:              && (INTVAL (offset) & 0x7) == 0)
                    731:            {
                    732:              if (op1 == operands[0])
                    733:                return "ldd %1,%0";
                    734:              else
                    735:                return "std %1,%0";
                    736:            }
                    737:        }
                    738:       else
                    739:        {
1.1.1.8   root      740:          /* We know structs not on the stack are properly aligned.
                    741:             Since a double asks for 8-byte alignment,
                    742:             we know it must have got that if it is in a struct.
                    743:             But a DImode need not be 8-byte aligned, because it could be a
                    744:             struct containing two ints or pointers.  */
                    745:          if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode
                    746:              && MEM_IN_STRUCT_P (operands[1]))
1.1.1.4   root      747:            return "ldd %1,%0";
1.1.1.8   root      748:          else if (GET_CODE (operands[0]) == MEM
                    749:                   && GET_MODE (operands[0]) == DFmode
                    750:                   && MEM_IN_STRUCT_P (operands[0]))
1.1.1.4   root      751:            return "std %1,%0";
                    752:        }
1.1.1.3   root      753:     }
1.1.1.4   root      754: 
1.1       root      755:   if (optype0 == REGOP && optype1 == REGOP
                    756:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    757:     {
                    758:       /* Make any unoffsetable addresses point at high-numbered word.  */
                    759:       if (addreg0)
                    760:        output_asm_insn ("add %0,0x4,%0", &addreg0);
                    761:       if (addreg1)
                    762:        output_asm_insn ("add %0,0x4,%0", &addreg1);
                    763: 
                    764:       /* Do that word.  */
                    765:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    766: 
                    767:       /* Undo the adds we just did.  */
                    768:       if (addreg0)
                    769:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    770:       if (addreg1)
                    771:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    772: 
                    773:       /* Do low-numbered word.  */
                    774:       return singlemove_string (operands);
                    775:     }
1.1.1.3   root      776:   else if (optype0 == REGOP && optype1 != REGOP
1.1.1.8   root      777:           && reg_overlap_mentioned_p (operands[0], operands[1]))
1.1.1.3   root      778:     {
                    779:       /* Do the late half first.  */
                    780:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    781:       /* Then clobber.  */
                    782:       return singlemove_string (operands);
                    783:     }
1.1       root      784: 
                    785:   /* Normal case: do the two words, low-numbered first.  */
                    786: 
                    787:   output_asm_insn (singlemove_string (operands), operands);
                    788: 
                    789:   /* Make any unoffsetable addresses point at high-numbered word.  */
                    790:   if (addreg0)
                    791:     output_asm_insn ("add %0,0x4,%0", &addreg0);
                    792:   if (addreg1)
                    793:     output_asm_insn ("add %0,0x4,%0", &addreg1);
                    794: 
                    795:   /* Do that word.  */
                    796:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    797: 
                    798:   /* Undo the adds we just did.  */
                    799:   if (addreg0)
                    800:     output_asm_insn ("add %0,-0x4,%0", &addreg0);
                    801:   if (addreg1)
                    802:     output_asm_insn ("add %0,-0x4,%0", &addreg1);
                    803: 
                    804:   return "";
                    805: }
                    806: 
                    807: static char *
                    808: output_fp_move_double (operands)
                    809:      rtx *operands;
                    810: {
                    811:   if (FP_REG_P (operands[0]))
                    812:     {
                    813:       if (FP_REG_P (operands[1]))
                    814:        {
                    815:          output_asm_insn ("fmovs %1,%0", operands);
                    816:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
                    817:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
                    818:          return "fmovs %1,%0";
                    819:        }
                    820:       if (GET_CODE (operands[1]) == REG)
                    821:        {
1.1.1.3   root      822:          if ((REGNO (operands[1]) & 1) == 0)
                    823:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
                    824:          else
                    825:            {
                    826:              rtx xoperands[3];
                    827:              xoperands[0] = operands[0];
                    828:              xoperands[1] = operands[1];
                    829:              xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    830:              output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands);
                    831:              return "";
                    832:            }
1.1       root      833:        }
1.1.1.4   root      834:       if (GET_CODE (XEXP (operands[1], 0)) == PLUS
                    835:          && (XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx
                    836:              || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx)
                    837:          && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT
                    838:          && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) != 0)
                    839:        {
                    840:          rtx xoperands[2];
                    841:          output_asm_insn ("ld %1,%0", operands);
                    842:          xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]),
                    843:                                  REGNO (operands[0]) + 1);
                    844:          xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]),
                    845:                                  plus_constant (XEXP (operands[1], 0), 4));
                    846:          output_asm_insn ("ld %1,%0", xoperands);
                    847:          return "";
                    848:        }
1.1.1.8   root      849:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
                    850:        {
                    851:          if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
                    852:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
                    853:            output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
                    854:          cc_status.flags |= CC_KNOW_HI_G1;
                    855:          cc_status.mdep = XEXP (operands[1], 0);
                    856:          return "ldd [%%lo(%m1)+%%g1],%0";
                    857:        }
1.1       root      858:       return "ldd %1,%0";
                    859:     }
                    860:   else if (FP_REG_P (operands[1]))
                    861:     {
                    862:       if (GET_CODE (operands[0]) == REG)
                    863:        {
1.1.1.3   root      864:          if ((REGNO (operands[0]) & 1) == 0)
                    865:            return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
                    866:          else
                    867:            {
                    868:              rtx xoperands[3];
                    869:              xoperands[2] = operands[1];
                    870:              xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    871:              xoperands[0] = operands[0];
                    872:              output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);
                    873:              return "";
                    874:            }
1.1       root      875:        }
1.1.1.4   root      876:       if (GET_CODE (XEXP (operands[0], 0)) == PLUS
                    877:          && (XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx
                    878:              || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx)
                    879:          && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT
                    880:          && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) != 0)
                    881:        {
                    882:          rtx xoperands[2];
1.1.1.8   root      883:          output_asm_insn ("st %r1,%0", operands);
1.1.1.4   root      884:          xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]),
                    885:                                  REGNO (operands[1]) + 1);
                    886:          xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]),
                    887:                                  plus_constant (XEXP (operands[0], 0), 4));
1.1.1.8   root      888:          output_asm_insn ("st %r1,%0", xoperands);
1.1.1.4   root      889:          return "";
                    890:        }
1.1.1.8   root      891:       if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
                    892:        {
                    893:          if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
                    894:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
                    895:            output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
                    896:          cc_status.flags |= CC_KNOW_HI_G1;
                    897:          cc_status.mdep = XEXP (operands[0], 0);
                    898:          return "std %1,[%%lo(%m0)+%%g1]";
                    899:        }
1.1       root      900:       return "std %1,%0";
                    901:     }
1.1.1.3   root      902:   else abort ();
1.1       root      903: }
                    904: 
                    905: /* Return a REG that occurs in ADDR with coefficient 1.
                    906:    ADDR can be effectively incremented by incrementing REG.  */
                    907: 
                    908: static rtx
                    909: find_addr_reg (addr)
                    910:      rtx addr;
                    911: {
                    912:   while (GET_CODE (addr) == PLUS)
                    913:     {
                    914:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    915:        addr = XEXP (addr, 0);
                    916:       if (GET_CODE (XEXP (addr, 1)) == REG)
                    917:        addr = XEXP (addr, 1);
                    918:       if (CONSTANT_P (XEXP (addr, 0)))
                    919:        addr = XEXP (addr, 1);
                    920:       if (CONSTANT_P (XEXP (addr, 1)))
                    921:        addr = XEXP (addr, 0);
                    922:     }
                    923:   if (GET_CODE (addr) == REG)
                    924:     return addr;
                    925:   return 0;
                    926: }
                    927: 
1.1.1.8   root      928: void
                    929: output_sized_memop (opname, mode)
                    930:      char *opname;
                    931:      enum machine_mode mode;
                    932: {
                    933:   extern struct _iobuf *asm_out_file;
                    934: 
                    935:   static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" };
                    936:   static char *st_size_suffix[] = { "b", "h", "", "?", "d" };
                    937:   char *modename
                    938:     = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1];
                    939: 
                    940:   fprintf (asm_out_file, "\t%s%s", opname, modename);
                    941: }
1.1.1.9 ! root      942: 
        !           943: /* Output a store-in-memory whose operands are OPERANDS[0,1].
        !           944:    OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.  */
        !           945: 
        !           946: char *
        !           947: output_store (operands)
        !           948:      rtx *operands;
        !           949: {
        !           950:   enum machine_mode mode = GET_MODE (operands[0]);
        !           951:   rtx address = XEXP (operands[0], 0);
        !           952: 
        !           953:   cc_status.flags |= CC_KNOW_HI_G1;
        !           954:   cc_status.mdep = address;
        !           955: 
        !           956:   if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
        !           957:         && address == cc_prev_status.mdep))
        !           958:     {
        !           959:       output_asm_insn ("sethi %%hi(%m0),%%g1", operands);
        !           960:       cc_prev_status.mdep = address;
        !           961:     }
        !           962: 
        !           963:   /* Store zero in two parts when appropriate.  */
        !           964:   if (mode == DFmode && operands[1] == dconst0_rtx)
        !           965:     {
        !           966:       /* We can't cross a page boundary here because the
        !           967:         SYMBOL_REF must be double word aligned, and for this
        !           968:         to be the case, SYMBOL_REF+4 cannot cross.  */
        !           969:       output_sized_memop ("st", SImode);
        !           970:       output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands);
        !           971:       output_sized_memop ("st", SImode);
        !           972:       return "%r1,[%%g1+%%lo(%m0)+4]";
        !           973:     }
        !           974: 
        !           975:   /* Code below isn't smart enough to move a doubleword in two parts,
        !           976:      so use output_move_double to do that in the cases that require it.  */
        !           977:   if ((mode == DImode || mode == DFmode)
        !           978:       && (GET_CODE (operands[1]) == REG
        !           979:          && (REGNO (operands[1]) & 1)))
        !           980:     return output_move_double (operands);
        !           981: 
        !           982:   output_sized_memop ("st", mode);
        !           983:   return "%r1,[%%g1+%%lo(%m0)]";
        !           984: }
        !           985: 
        !           986: /* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1].
        !           987:    OPERANDS[0] is a reg, and OPERANDS[1] is a mem.  */
        !           988: 
        !           989: char *
        !           990: output_load_fixed (operands)
        !           991:      rtx *operands;
        !           992: {
        !           993:   enum machine_mode mode = GET_MODE (operands[0]);
        !           994:   rtx address = XEXP (operands[1], 0);
        !           995: 
        !           996:   /* We don't bother trying to see if we know %hi(address).
        !           997:      This is because we are doing a load, and if we know the
        !           998:      %hi value, we probably also know that value in memory.  */
        !           999:   cc_status.flags |= CC_KNOW_HI_G1;
        !          1000:   cc_status.mdep = address;
        !          1001: 
        !          1002:   if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
        !          1003:         && address == cc_prev_status.mdep
        !          1004:         && cc_prev_status.mdep == cc_status.mdep))
        !          1005:     {
        !          1006:       output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
        !          1007:       cc_prev_status.mdep = address;
        !          1008:     }
        !          1009: 
        !          1010:   /* Code below isn't smart enough to do a doubleword in two parts.
        !          1011:      So handle that case the slow way.  */
        !          1012:   if (mode == DImode
        !          1013:       && GET_CODE (operands[0]) == REG   /* Moving to nonaligned reg pair */
        !          1014:       && (REGNO (operands[0]) & 1))
        !          1015:     return output_move_double (operands);
        !          1016: 
        !          1017:   output_sized_memop ("ld", mode);
        !          1018:   if (GET_CODE (operands[0]) == REG)
        !          1019:     return "[%%g1+%%lo(%m1)],%0";
        !          1020:   abort ();
        !          1021: }
        !          1022: 
        !          1023: /* Output a floating-point load-from-memory whose operands are OPERANDS[0,1].
        !          1024:    OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
        !          1025:    We also handle the case where OPERANDS[0] is a mem.  */
        !          1026: 
        !          1027: char *
        !          1028: output_load_floating (operands)
        !          1029:      rtx *operands;
        !          1030: {
        !          1031:   enum machine_mode mode = GET_MODE (operands[0]);
        !          1032:   rtx address = XEXP (operands[1], 0);
1.1.1.8   root     1033: 
1.1.1.9 ! root     1034:   /* We don't bother trying to see if we know %hi(address).
        !          1035:      This is because we are doing a load, and if we know the
        !          1036:      %hi value, we probably also know that value in memory.  */
        !          1037:   cc_status.flags |= CC_KNOW_HI_G1;
        !          1038:   cc_status.mdep = address;
        !          1039: 
        !          1040:   if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
        !          1041:         && address == cc_prev_status.mdep
        !          1042:         && cc_prev_status.mdep == cc_status.mdep))
        !          1043:     {
        !          1044:       output_asm_insn ("sethi %%hi(%m1),%%g1", operands);
        !          1045:       cc_prev_status.mdep = address;
        !          1046:     }
        !          1047: 
        !          1048:   if (mode == DFmode)
        !          1049:     {
        !          1050:       if (REG_P (operands[0]))
        !          1051:        {
        !          1052:          if (REGNO (operands[0]) & 1)
        !          1053:            return output_move_double (operands);
        !          1054:          else
        !          1055:            return "ldd [%%g1+%%lo(%m1)],%0";
        !          1056:        }
        !          1057:       cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0);
        !          1058:       output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands);
        !          1059:       operands[1] = gen_rtx (REG, DFmode, 32);
        !          1060:       return output_fp_move_double (operands);
        !          1061:     }
        !          1062: 
        !          1063:   if (GET_CODE (operands[0]) == MEM)
        !          1064:     {
        !          1065:       cc_status.flags &= ~CC_F1_IS_0;
        !          1066:       output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands);
        !          1067:       if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
        !          1068:        {
        !          1069:          cc_status.mdep = XEXP (operands[0], 0);
        !          1070:          return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]";
        !          1071:        }
        !          1072:       else
        !          1073:        return "st %%f1,%0";
        !          1074:     }
        !          1075:   return "ld [%%g1+%%lo(%m1)],%0";
        !          1076: }
        !          1077: 
1.1       root     1078: /* Load the address specified by OPERANDS[3] into the register
                   1079:    specified by OPERANDS[0].
                   1080: 
                   1081:    OPERANDS[3] may be the result of a sum, hence it could either be:
                   1082: 
                   1083:    (1) CONST
                   1084:    (2) REG
                   1085:    (2) REG + CONST_INT
                   1086:    (3) REG + REG + CONST_INT
1.1.1.8   root     1087:    (4) REG + REG  (special case of 3).
1.1       root     1088: 
1.1.1.5   root     1089:    Note that (3) is not a legitimate address.
1.1       root     1090:    All cases are handled here.  */
                   1091: 
                   1092: void
                   1093: output_load_address (operands)
                   1094:      rtx *operands;
                   1095: {
                   1096:   rtx base, offset;
                   1097: 
                   1098:   if (CONSTANT_P (operands[3]))
                   1099:     {
                   1100:       output_asm_insn ("set %3,%0", operands);
                   1101:       return;
                   1102:     }
                   1103: 
                   1104:   if (REG_P (operands[3]))
                   1105:     {
                   1106:       if (REGNO (operands[0]) != REGNO (operands[3]))
                   1107:        output_asm_insn ("mov %3,%0", operands);
                   1108:       return;
                   1109:     }
                   1110: 
1.1.1.8   root     1111:   if (GET_CODE (operands[3]) != PLUS)
                   1112:     abort ();
                   1113: 
1.1       root     1114:   base = XEXP (operands[3], 0);
                   1115:   offset = XEXP (operands[3], 1);
                   1116: 
                   1117:   if (GET_CODE (base) == CONST_INT)
                   1118:     {
                   1119:       rtx tmp = base;
                   1120:       base = offset;
                   1121:       offset = tmp;
                   1122:     }
                   1123: 
                   1124:   if (GET_CODE (offset) != CONST_INT)
1.1.1.8   root     1125:     {
                   1126:       /* Operand is (PLUS (REG) (REG)).  */
                   1127:       base = operands[3];
                   1128:       offset = const0_rtx;
                   1129:     }
1.1       root     1130: 
                   1131:   if (REG_P (base))
                   1132:     {
                   1133:       operands[6] = base;
                   1134:       operands[7] = offset;
                   1135:       if (SMALL_INT (offset))
                   1136:        output_asm_insn ("add %6,%7,%0", operands);
                   1137:       else
                   1138:        output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
                   1139:     }
1.1.1.8   root     1140:   else if (GET_CODE (base) == PLUS)
1.1       root     1141:     {
                   1142:       operands[6] = XEXP (base, 0);
                   1143:       operands[7] = XEXP (base, 1);
                   1144:       operands[8] = offset;
                   1145: 
                   1146:       if (SMALL_INT (offset))
                   1147:        output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
                   1148:       else
                   1149:        output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
                   1150:     }
1.1.1.8   root     1151:   else
                   1152:     abort ();
1.1       root     1153: }
                   1154: 
1.1.1.5   root     1155: /* Output code to place a size count SIZE in register REG.
                   1156:    If SIZE is round, then assume that we can use alignment
                   1157:    based on that roundness, and return an integer saying
                   1158:    what alignment (roundness, transfer size) we will be using.
                   1159: 
                   1160:    Because block moves are pipelined, we don't include the
                   1161:    first element in the transfer of SIZE to REG.  */
                   1162: 
                   1163: static int
                   1164: output_size_for_block_move (size, reg)
                   1165:      rtx size, reg;
                   1166: {
                   1167:   int align;
                   1168:   rtx xoperands[2];
                   1169:   xoperands[0] = reg;
                   1170: 
                   1171:   /* First, figure out best alignment we may assume.  */
                   1172:   if (REG_P (size))
                   1173:     {
                   1174:       xoperands[1] = size;
                   1175:       output_asm_insn ("sub %1,1,%0", xoperands);
                   1176:       align = 1;
                   1177:     }
                   1178:   else
                   1179:     {
                   1180:       int i = INTVAL (size);
                   1181: 
                   1182:       if (i & 1)
                   1183:        align = 1;
                   1184:       else if (i & 3)
                   1185:        align = 2;
                   1186:       else
                   1187:        align = 4;
                   1188: 
                   1189:       /* predecrement count.  */
                   1190:       i -= align;
                   1191:       if (i < 0) abort ();
                   1192: 
                   1193:       xoperands[1] = gen_rtx (CONST_INT, VOIDmode, i);
                   1194: 
                   1195:       output_asm_insn ("set %1,%0", xoperands);
                   1196:     }
                   1197:   return align;
                   1198: }
                   1199: 
                   1200: /* Emit code to perform a block move.
                   1201: 
                   1202:    OPERANDS[0] is the destination.
                   1203:    OPERANDS[1] is the source.
                   1204:    OPERANDS[2] is the size.
1.1.1.8   root     1205:    OPERANDS[3..5] are pseudos we can safely clobber as temps.  */
1.1.1.5   root     1206: 
1.1       root     1207: char *
                   1208: output_block_move (operands)
                   1209:      rtx *operands;
                   1210: {
1.1.1.5   root     1211:   /* A vector for our computed operands.  Note that load_output_address
1.1.1.8   root     1212:      makes use of (and can clobber) up to the 8th element of this vector.  */
1.1.1.5   root     1213:   rtx xoperands[10];
1.1.1.8   root     1214:   rtx zoperands[10];
1.1       root     1215:   static int movstrsi_label = 0;
1.1.1.5   root     1216:   int align = -1;              /* not yet known */
1.1       root     1217:   int i, j;
                   1218: 
1.1.1.8   root     1219:   xoperands[0] = operands[0];
                   1220:   xoperands[1] = operands[1];
                   1221:   xoperands[2] = operands[3];
1.1.1.5   root     1222: 
1.1       root     1223:   /* Since we clobber untold things, nix the condition codes.  */
                   1224:   CC_STATUS_INIT;
                   1225: 
1.1.1.5   root     1226:   /* Recognize special cases of block moves.  These occur
                   1227:      when GNU C++ is forced to treat something as BLKmode
                   1228:      to keep it in memory, when its mode could be represented
1.1.1.8   root     1229:      with something smaller.
                   1230: 
                   1231:      We cannot do this for global variables, since we don't know
                   1232:      what pages they don't cross.  Sigh.  */
1.1.1.5   root     1233:   if (GET_CODE (operands[2]) == CONST_INT
1.1.1.8   root     1234:       && INTVAL (operands[2]) <= 16
                   1235:       && ! CONSTANT_ADDRESS_P (operands[0])
                   1236:       && ! CONSTANT_ADDRESS_P (operands[1]))
1.1.1.5   root     1237:     {
                   1238:       int size = INTVAL (operands[2]);
                   1239: 
1.1.1.8   root     1240:       cc_status.flags &= ~CC_KNOW_HI_G1;
1.1.1.5   root     1241:       if (size & 1)
                   1242:        {
                   1243:          if (memory_address_p (QImode, plus_constant (xoperands[0], size))
                   1244:              && memory_address_p (QImode, plus_constant (xoperands[1], size)))
                   1245:            {
1.1.1.8   root     1246:              /* We will store different integers into this particular RTX.  */
                   1247:              xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1.1.1.5   root     1248:              for (i = size-1; i >= 0; i--)
                   1249:                {
                   1250:                  INTVAL (xoperands[2]) = i;
                   1251:                  output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
                   1252:                                   xoperands);
                   1253:                }
                   1254:              return "";
                   1255:            }
                   1256:        }
                   1257:       else if (size & 2)
                   1258:        {
                   1259:          if (memory_address_p (HImode, plus_constant (xoperands[0], size))
                   1260:              && memory_address_p (HImode, plus_constant (xoperands[1], size)))
                   1261:            {
1.1.1.8   root     1262:              /* We will store different integers into this particular RTX.  */
                   1263:              xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1.1.1.5   root     1264:              for (i = (size>>1)-1; i >= 0; i--)
                   1265:                {
                   1266:                  INTVAL (xoperands[2]) = i<<1;
                   1267:                  output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
                   1268:                                   xoperands);
                   1269:                }
                   1270:              return "";
                   1271:            }
                   1272:        }
                   1273:       else
                   1274:        {
                   1275:          if (memory_address_p (SImode, plus_constant (xoperands[0], size))
                   1276:              && memory_address_p (SImode, plus_constant (xoperands[1], size)))
                   1277:            {
1.1.1.8   root     1278:              /* We will store different integers into this particular RTX.  */
                   1279:              xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13);
1.1.1.5   root     1280:              for (i = (size>>2)-1; i >= 0; i--)
                   1281:                {
                   1282:                  INTVAL (xoperands[2]) = i<<2;
                   1283:                  output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
                   1284:                                   xoperands);
                   1285:                }
                   1286:              return "";
                   1287:            }
                   1288:        }
                   1289:     }
                   1290: 
1.1.1.8   root     1291:   /* This is the size of the transfer.
                   1292:      Either use the register which already contains the size,
                   1293:      or use a free register (used by no operands).
                   1294:      Also emit code to decrement the size value by ALIGN.  */
                   1295:   align = output_size_for_block_move (operands[2], operands[3]);
1.1.1.5   root     1296:      
1.1.1.8   root     1297:   zoperands[0] = operands[0];
                   1298:   zoperands[3] = plus_constant (operands[0], align);
                   1299:   output_load_address (zoperands);
1.1       root     1300: 
                   1301:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1302:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
                   1303: 
1.1.1.5   root     1304:   if (align == 1)
                   1305:     output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands);
                   1306:   else if (align == 2)
                   1307:     output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands);
                   1308:   else
                   1309:     output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands);
1.1       root     1310:   return "";
                   1311: }
1.1.1.5   root     1312: 
                   1313: /* What the sparc lacks in hardware, make up for in software.
                   1314:    Compute a fairly good sequence of shift and add insns
                   1315:    to make a multiply happen.  */
1.1       root     1316: 
                   1317: #define ABS(x) ((x) < 0 ? -(x) : x)
                   1318: 
                   1319: char *
                   1320: output_mul_by_constant (insn, operands, unsignedp)
                   1321:      rtx insn;
                   1322:      rtx *operands;
                   1323:      int unsignedp;
                   1324: {
                   1325:   int c;                       /* Size of constant */
                   1326:   int shifts[BITS_PER_WORD];   /* Table of shifts */
1.1.1.4   root     1327:   unsigned int p, log;         /* A power of two, and its log */
1.1       root     1328:   int d1, d2;                  /* Differences of c and p */
                   1329:   int first = 1;               /* True if dst has unknown data in it */
                   1330:   int i;
                   1331: 
                   1332:   c = INTVAL (operands[2]);
                   1333:   if (c == 0)
                   1334:     {
                   1335:       /* should not happen.  */
                   1336:       abort ();
                   1337:       if (GET_CODE (operands[0]) == MEM)
                   1338:        return "st %%g0,%0";
                   1339:       return "mov %%g0,%0";
                   1340:     }
                   1341: 
                   1342:   output_asm_insn ("! start open coded multiply");
                   1343: 
                   1344:   /* Clear out the table of shifts. */
                   1345:   for (i = 0; i < BITS_PER_WORD; ++i)
                   1346:     shifts[i] = 0;
                   1347: 
                   1348:   while (c)
                   1349:     {
                   1350:       /* Find the power of two nearest ABS(c) */
                   1351:       p = 1, log = 0;
                   1352:       do
                   1353:        {
                   1354:          d1 = ABS(c) - p;
                   1355:          p *= 2;
                   1356:          ++log;
                   1357:        }
                   1358:       while (p < ABS(c));
                   1359:       d2 = p - ABS(c);
                   1360: 
                   1361:       /* Make an appropriate entry in shifts for p. */
                   1362:       if (d2 < d1)
                   1363:        {
                   1364:          shifts[log] = c < 0 ? -1 : 1;
                   1365:          c = c < 0 ? d2 : -d2;
                   1366:        }
                   1367:       else
                   1368:        {
                   1369:          shifts[log - 1] = c < 0 ? -1 : 1;
                   1370:          c = c < 0 ? -d1 : d1;
                   1371:        }
                   1372:     }
                   1373: 
                   1374:   /* Take care of the first insn in sequence.
                   1375:      We know we have at least one. */
                   1376: 
                   1377:   /* A value of -1 in shifts says to subtract that power of two, and a value
                   1378:      of 1 says to add that power of two. */
                   1379:   for (i = 0; ; i++)
                   1380:     if (shifts[i])
                   1381:       {
                   1382:        if (i)
                   1383:          {
                   1384:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i);
1.1.1.5   root     1385:            output_asm_insn ("sll %1,%2,%%g1", operands);
1.1       root     1386:          }
1.1.1.5   root     1387:        else output_asm_insn ("mov %1,%%g1", operands);
1.1       root     1388: 
                   1389:        log = i;
                   1390:        if (shifts[i] < 0)
1.1.1.5   root     1391:          output_asm_insn ("sub %%g0,%%g1,%0", operands);
1.1       root     1392:        else
1.1.1.5   root     1393:          output_asm_insn ("mov %%g1,%0", operands);
1.1       root     1394:        break;
                   1395:       }
                   1396: 
                   1397:   /* A value of -1 in shifts says to subtract that power of two, and a value
                   1398:      of 1 says to add that power of two--continued.  */
                   1399:   for (i += 1; i < BITS_PER_WORD; ++i)
                   1400:     if (shifts[i])
                   1401:       {
                   1402:        if (i - log > 0)
                   1403:          {
                   1404:            operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log);
1.1.1.5   root     1405:            output_asm_insn ("sll %%g1,%2,%%g1", operands);
1.1       root     1406:          }
                   1407:        else
                   1408:          {
                   1409:            operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i);
1.1.1.5   root     1410:            output_asm_insn ("sra %%g1,%2,%%g1", operands);
1.1       root     1411:          }
                   1412:        log = i;
                   1413:        if (shifts[i] < 0)
1.1.1.5   root     1414:          output_asm_insn ("sub %0,%%g1,%0", operands);
1.1       root     1415:        else
1.1.1.5   root     1416:          output_asm_insn ("add %0,%%g1,%0", operands);
1.1       root     1417:       }
                   1418: 
                   1419:   output_asm_insn ("! end open coded multiply");
                   1420: 
                   1421:   return "";
                   1422: }
                   1423: 
                   1424: char *
                   1425: output_mul_insn (operands, unsignedp)
                   1426:      rtx *operands;
                   1427:      int unsignedp;
                   1428: {
                   1429:   int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1;
                   1430:   int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1;
                   1431: 
                   1432:   if (lucky1)
                   1433:     if (lucky2)
                   1434:       output_asm_insn ("call .mul,2\n\tnop", operands);
                   1435:     else
                   1436:       {
                   1437:        rtx xoperands[2];
                   1438:        xoperands[0] = gen_rtx (REG, SImode,
                   1439:                                8 ^ (REGNO (operands[1]) == 8));
                   1440:        xoperands[1] = operands[2];
                   1441:        output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                   1442:       }
                   1443:   else if (lucky2)
                   1444:     {
                   1445:       rtx xoperands[2];
                   1446:       xoperands[0] = gen_rtx (REG, SImode,
                   1447:                              8 ^ (REGNO (operands[2]) == 8));
                   1448:       xoperands[1] = operands[1];
                   1449:       output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
                   1450:     }
                   1451:   else
                   1452:     {
                   1453:       output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1",
                   1454:                       operands);
                   1455:     }
                   1456: 
                   1457:   if (REGNO (operands[0]) == 8)
                   1458:     return "";
                   1459:   return "mov %%o0,%0";
                   1460: }
                   1461: 
                   1462: /* Make floating point register f0 contain 0.
                   1463:    SIZE is the number of registers (including f0)
                   1464:    which should contain 0.  */
                   1465: 
                   1466: void
                   1467: make_f0_contain_0 (size)
                   1468:      int size;
                   1469: {
                   1470:   if (size == 1)
1.1.1.8   root     1471:     {
                   1472:       if ((cc_status.flags & (CC_F0_IS_0)) == 0)
                   1473:        output_asm_insn ("ld [%%fp-16],%%f0", 0);
                   1474:       cc_status.flags |= CC_F0_IS_0;
                   1475:     }
1.1       root     1476:   else if (size == 2)
1.1.1.8   root     1477:     {
                   1478:       if ((cc_status.flags & CC_F0_IS_0) == 0)
                   1479:        output_asm_insn ("ld [%%fp-16],%%f0", 0);
                   1480:       if ((cc_status.flags & (CC_F1_IS_0)) == 0)
                   1481:        output_asm_insn ("ld [%%fp-12],%%f1", 0);
                   1482:       cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0;
                   1483:     }
                   1484: }
                   1485: 
                   1486: /* Since condition codes don't have logical links, we need to keep
                   1487:    their setting and use together for set-cc insns.  */
                   1488: void
                   1489: gen_scc_insn (code, mode, operands)
                   1490:      enum rtx_code code;
                   1491:      enum machine_mode mode;
                   1492:      rtx *operands;
                   1493: {
                   1494:   extern rtx sequence_stack;
                   1495:   rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0);
                   1496:   rtx last_pat = PATTERN (last_insn);
                   1497:   if (GET_CODE (last_pat) != SET
                   1498:       || GET_CODE (SET_DEST (last_pat)) != CC0)
                   1499:     abort ();
                   1500:   SET_DEST (last_pat) = operands[0];
                   1501:   SET_SRC (last_pat) = gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx);
1.1       root     1502: }
1.1.1.4   root     1503: 
                   1504: /* Output reasonable peephole for set-on-condition-code insns.
                   1505:    Note that these insns assume a particular way of defining
                   1506:    labels.  Therefore, *both* tm-sparc.h and this function must
                   1507:    be changed if a new syntax is needed.  */
                   1508: 
                   1509: char *
1.1.1.8   root     1510: output_scc_insn (code, operand)
1.1.1.4   root     1511:      enum rtx_code code;
1.1.1.8   root     1512:      rtx operand;
1.1.1.4   root     1513: {
                   1514:   rtx xoperands[2];
                   1515:   rtx label = gen_label_rtx ();
1.1.1.8   root     1516:   int cc_in_fccr = cc_status.flags & CC_IN_FCCR;
1.1.1.4   root     1517: 
1.1.1.8   root     1518:   xoperands[0] = operand;
1.1.1.4   root     1519:   xoperands[1] = label;
                   1520: 
                   1521:   switch (code)
                   1522:     {
                   1523:     case NE:
1.1.1.8   root     1524:       if (cc_in_fccr)
1.1.1.5   root     1525:        output_asm_insn ("fbne,a %l0", &label);
1.1.1.4   root     1526:       else
1.1.1.5   root     1527:        output_asm_insn ("bne,a %l0", &label);
1.1.1.4   root     1528:       break;
                   1529:     case EQ:
1.1.1.8   root     1530:       if (cc_in_fccr)
1.1.1.5   root     1531:        output_asm_insn ("fbe,a %l0", &label);
1.1.1.4   root     1532:       else
1.1.1.5   root     1533:        output_asm_insn ("be,a %l0", &label);
1.1.1.4   root     1534:       break;
                   1535:     case GE:
1.1.1.8   root     1536:       if (cc_in_fccr)
1.1.1.5   root     1537:        output_asm_insn ("fbge,a %l0", &label);
1.1.1.4   root     1538:       else
1.1.1.5   root     1539:        output_asm_insn ("bge,a %l0", &label);
1.1.1.4   root     1540:       break;
                   1541:     case GT:
1.1.1.8   root     1542:       if (cc_in_fccr)
1.1.1.5   root     1543:        output_asm_insn ("fbg,a %l0", &label);
1.1.1.4   root     1544:       else
1.1.1.5   root     1545:        output_asm_insn ("bg,a %l0", &label);
1.1.1.4   root     1546:       break;
                   1547:     case LE:
1.1.1.8   root     1548:       if (cc_in_fccr)
1.1.1.5   root     1549:        output_asm_insn ("fble,a %l0", &label);
1.1.1.4   root     1550:       else
1.1.1.5   root     1551:        output_asm_insn ("ble,a %l0", &label);
1.1.1.4   root     1552:       break;
                   1553:     case LT:
1.1.1.8   root     1554:       if (cc_in_fccr)
1.1.1.5   root     1555:        output_asm_insn ("fbl,a %l0", &label);
1.1.1.4   root     1556:       else
1.1.1.5   root     1557:        output_asm_insn ("bl,a %l0", &label);
1.1.1.4   root     1558:       break;
                   1559:     case GEU:
1.1.1.8   root     1560:       if (cc_in_fccr)
1.1.1.4   root     1561:        abort ();
                   1562:       else
1.1.1.5   root     1563:        output_asm_insn ("bgeu,a %l0", &label);
1.1.1.4   root     1564:       break;
                   1565:     case GTU:
1.1.1.8   root     1566:       if (cc_in_fccr)
1.1.1.4   root     1567:        abort ();
                   1568:       else
1.1.1.5   root     1569:        output_asm_insn ("bgu,a %l0", &label);
1.1.1.4   root     1570:       break;
                   1571:     case LEU:
1.1.1.8   root     1572:       if (cc_in_fccr)
1.1.1.4   root     1573:        abort ();
                   1574:       else
1.1.1.5   root     1575:        output_asm_insn ("bleu,a %l0", &label);
1.1.1.4   root     1576:       break;
                   1577:     case LTU:
1.1.1.8   root     1578:       if (cc_in_fccr)
1.1.1.4   root     1579:        abort ();
                   1580:       else
1.1.1.5   root     1581:        output_asm_insn ("blu,a %l0", &label);
1.1.1.4   root     1582:       break;
                   1583:     default:
                   1584:       abort ();
                   1585:     }
1.1.1.8   root     1586:   output_asm_insn ("mov 1,%0\n\tmov 0,%0\n%l1:", xoperands);
1.1.1.4   root     1587:   return "";
                   1588: }
                   1589: 
1.1.1.5   root     1590: /* Output a delayed branch insn with the delay insn in its
                   1591:    branch slot.  The delayed branch insn template is in TEMPLATE,
1.1.1.8   root     1592:    with operands OPERANDS.  The insn in its delay slot is INSN.
                   1593: 
                   1594:    As a special case, since we know that all memory transfers are via
                   1595:    ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
                   1596:    reference around the branch as
                   1597: 
                   1598:        sethi %hi(x),%%g1
                   1599:        b ...
                   1600:        ld/st [%g1+%lo(x)],...
                   1601: 
1.1.1.9 ! root     1602:    As another special case, we handle loading (SYMBOL_REF ...) and
        !          1603:    other large constants around branches as well:
        !          1604: 
        !          1605:        sethi %hi(x),%0
        !          1606:        b ...
        !          1607:        or %0,%lo(x),%1
        !          1608: 
1.1.1.8   root     1609:    */
1.1.1.4   root     1610: 
                   1611: char *
1.1.1.9 ! root     1612: output_delayed_branch (template, operands, insn)
1.1.1.4   root     1613:      char *template;
                   1614:      rtx *operands;
                   1615:      rtx insn;
                   1616: {
1.1.1.9 ! root     1617:   extern rtx recog_operand[];
1.1.1.8   root     1618:   rtx src = XVECEXP (PATTERN (insn), 0, 1);
                   1619:   rtx dest = XVECEXP (PATTERN (insn), 0, 0);
                   1620: 
1.1.1.9 ! root     1621:   if (GET_CODE (src) == SYMBOL_REF
        !          1622:       || (GET_CODE (src) == CONST_INT
        !          1623:          && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0)))
        !          1624:     {
        !          1625:       rtx xoperands[2];
        !          1626:       xoperands[0] = dest;
        !          1627:       xoperands[1] = src;
        !          1628: 
        !          1629:       /* Output the `sethi' insn.  */
        !          1630:       output_asm_insn ("sethi %%hi(%1),%0", xoperands);
        !          1631: 
        !          1632:       /* Output the branch instruction next.  */
        !          1633:       output_asm_insn (template, operands);
        !          1634: 
        !          1635:       /* Now output the `or' insn.  */
        !          1636:       output_asm_insn ("or %0,%%lo(%1),%0", xoperands);
        !          1637:     }
        !          1638:   else if ((GET_CODE (src) == MEM
        !          1639:            && CONSTANT_ADDRESS_P (XEXP (src, 0)))
        !          1640:           || (GET_CODE (dest) == MEM
        !          1641:               && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
1.1.1.8   root     1642:     {
                   1643:       rtx xoperands[2];
                   1644:       char *split_template;
                   1645:       xoperands[0] = dest;
                   1646:       xoperands[1] = src;
                   1647: 
                   1648:       /* Output the `sethi' insn.  */
                   1649:       if (GET_CODE (src) == MEM)
                   1650:        {
1.1.1.9 ! root     1651:          if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
        !          1652:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
        !          1653:            output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands);
1.1.1.8   root     1654:          split_template = "ld [%%g1+%%lo(%m1)],%0";
                   1655:        }
                   1656:       else
                   1657:        {
1.1.1.9 ! root     1658:          if (! ((cc_prev_status.flags & CC_KNOW_HI_G1)
        !          1659:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
        !          1660:            output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands);
1.1.1.8   root     1661:          split_template = "st %r1,[%%g1+%%lo(%m0)]";
                   1662:        }
1.1.1.4   root     1663: 
1.1.1.8   root     1664:       /* Output the branch instruction next.  */
                   1665:       output_asm_insn (template, operands);
                   1666: 
                   1667:       /* Now output the load or store.
                   1668:         No need to do a CC_STATUS_INIT, because we are branching anyway.  */
                   1669:       output_asm_insn (split_template, xoperands);
                   1670:     }
                   1671:   else
                   1672:     {
                   1673:       extern char *insn_template[];
                   1674:       extern char *(*insn_outfun[])();
                   1675:       int insn_code_number;
                   1676:       rtx pat = gen_rtx (SET, VOIDmode, dest, src);
                   1677:       rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
                   1678: 
                   1679:       /* Output the branch instruction first.  */
                   1680:       output_asm_insn (template, operands);
                   1681: 
                   1682:       /* Now recognize the insn which we put in its delay slot.
                   1683:         We must do this after outputing the branch insn,
1.1.1.9 ! root     1684:         since operands may just be a pointer to `recog_operand'.  */
1.1.1.8   root     1685:       insn_code_number = recog (pat, delay_insn);
                   1686:       if (insn_code_number == -1)
                   1687:        abort ();
                   1688: 
                   1689:       /* Now get the template for what this insn would
                   1690:         have been, without the branch.  Its operands are
                   1691:         exactly the same as they would be, so we don't
                   1692:         need to do an insn_extract.  */
                   1693:       template = insn_template[insn_code_number];
                   1694:       if (template == 0)
1.1.1.9 ! root     1695:        template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
        !          1696:       output_asm_insn (template, recog_operand);
1.1.1.8   root     1697:     }
1.1.1.9 ! root     1698:   CC_STATUS_INIT;
1.1.1.4   root     1699:   return "";
                   1700: }
1.1.1.9 ! root     1701: 
        !          1702: /* Output a newly constructed insn DELAY_INSN.  */
        !          1703: char *
        !          1704: output_delay_insn (delay_insn)
        !          1705:      rtx delay_insn;
        !          1706: {
        !          1707:   char *template;
        !          1708:   extern rtx recog_operand[];
        !          1709:   extern char call_used_regs[];
        !          1710:   extern char *insn_template[];
        !          1711:   extern int insn_n_operands[];
        !          1712:   extern char *(*insn_outfun[])();
        !          1713:   extern rtx alter_subreg();
        !          1714:   int insn_code_number;
        !          1715:   extern int insn_n_operands[];
        !          1716:   int i;
        !          1717: 
        !          1718:   /* Now recognize the insn which we put in its delay slot.
        !          1719:      We must do this after outputing the branch insn,
        !          1720:      since operands may just be a pointer to `recog_operand'.  */
        !          1721:   insn_code_number = recog_memoized (delay_insn);
        !          1722:   if (insn_code_number == -1)
        !          1723:     abort ();
        !          1724: 
        !          1725:   /* Extract the operands of this delay insn.  */
        !          1726:   INSN_CODE (delay_insn) = insn_code_number;
        !          1727:   insn_extract (delay_insn);
        !          1728: 
        !          1729:   /* It is possible that this insn has not been properly scaned by final
        !          1730:      yet.  If this insn's operands don't appear in the peephole's
        !          1731:      actual operands, then they won't be fixed up by final, so we
        !          1732:      make sure they get fixed up here.  -- This is a kludge.  */
        !          1733:   for (i = 0; i < insn_n_operands[insn_code_number]; i++)
        !          1734:     {
        !          1735:       if (GET_CODE (recog_operand[i]) == SUBREG)
        !          1736:        recog_operand[i] = alter_subreg (recog_operand[i]);
        !          1737:     }
        !          1738: 
        !          1739: #ifdef REGISTER_CONSTRAINTS
        !          1740:   if (! constrain_operands (insn_code_number))
        !          1741:     abort ();
        !          1742: #endif
        !          1743: 
        !          1744:   cc_prev_status = cc_status;
        !          1745: 
        !          1746:   /* Update `cc_status' for this instruction.
        !          1747:      The instruction's output routine may change it further.
        !          1748:      If the output routine for a jump insn needs to depend
        !          1749:      on the cc status, it should look at cc_prev_status.  */
        !          1750: 
        !          1751:   NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
        !          1752: 
        !          1753:   /* Now get the template for what this insn would
        !          1754:      have been, without the branch.  */
        !          1755: 
        !          1756:   template = insn_template[insn_code_number];
        !          1757:   if (template == 0)
        !          1758:     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
        !          1759:   output_asm_insn (template, recog_operand);
        !          1760:   return "";
        !          1761: }
        !          1762: 
        !          1763: /* Output the insn HEAD, keeping OPERANDS protected (wherever they are).
        !          1764:    HEAD comes from the target of some branch, so before we output it,
        !          1765:    we delete it from the target, lest we execute it twice.  The caller
        !          1766:    of this function promises that such code motion is permissable.  */
        !          1767: char *
        !          1768: output_eager_then_insn (head, operands)
        !          1769:      rtx head;
        !          1770:      rtx *operands;
        !          1771: {
        !          1772:   extern rtx alter_subreg ();
        !          1773:   extern int insn_n_operands[];
        !          1774:   extern rtx recog_operand[];
        !          1775:   rtx xoperands[MAX_RECOG_OPERANDS];
        !          1776:   int insn_code_number, i, nbytes;
        !          1777:   rtx nhead;
        !          1778: 
        !          1779:   /* Micro-hack: run peephole on head if it looks like a good idea.
        !          1780:      Right now there's only one such case worth doing...
        !          1781: 
        !          1782:      This could be made smarter if the peephole for ``2-insn combine''
        !          1783:      were also made smarter.  */
        !          1784:   if (GET_CODE (PATTERN (head)) == SET
        !          1785:       && REG_P (SET_SRC (PATTERN (head)))
        !          1786:       && REG_P (SET_DEST (PATTERN (head)))
        !          1787:       && (nhead = next_real_insn_no_labels (head))
        !          1788:       && GET_CODE (nhead) == INSN
        !          1789:       && GET_CODE (PATTERN (nhead)) == SET
        !          1790:       && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0
        !          1791:       && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head))
        !          1792:          || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head))))
        !          1793:     /* Something's wrong if this does not fly.  */
        !          1794:     if (! peephole (head))
        !          1795:       abort ();
        !          1796: 
        !          1797:   /* Save our contents of `operands', since output_delay_insn sets them.  */
        !          1798:   insn_code_number = recog_memoized (head);
        !          1799:   nbytes = insn_n_operands[insn_code_number] * sizeof (rtx);
        !          1800:   bcopy (operands, xoperands, nbytes);
        !          1801: 
        !          1802:   /* Output the delay insn, and prevent duplication later.  */
        !          1803:   delete_insn (head);
        !          1804:   output_delay_insn (head);
        !          1805: 
        !          1806:   /* Restore this insn's operands.  */
        !          1807:   bcopy (xoperands, operands, nbytes);
        !          1808: }
        !          1809: 
        !          1810: /* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL;
        !          1811:    or 0, if there is none.  Also return 0 if we cross a label.  */
        !          1812: 
        !          1813: rtx
        !          1814: next_real_insn_no_labels (label)
        !          1815:      rtx label;
        !          1816: {
        !          1817:   register rtx insn = NEXT_INSN (label);
        !          1818:   register RTX_CODE code;
        !          1819: 
        !          1820:   while (insn)
        !          1821:     {
        !          1822:       code = GET_CODE (insn);
        !          1823:       if (code == INSN)
        !          1824:        {
        !          1825:          if (GET_CODE (PATTERN (insn)) != CLOBBER
        !          1826:              && GET_CODE (PATTERN (insn)) != USE)
        !          1827:            return insn;
        !          1828:        }
        !          1829:       if (code == CALL_INSN || code == JUMP_INSN)
        !          1830:        return insn;
        !          1831:       if (code == CODE_LABEL)
        !          1832:        return 0;
        !          1833:       insn = NEXT_INSN (insn);
        !          1834:     }
        !          1835: 
        !          1836:   return 0;
        !          1837: }
        !          1838: 
        !          1839: int
        !          1840: operands_satisfy_eager_branch_peephole (operands, conditional)
        !          1841:      rtx *operands;
        !          1842:      int conditional;
        !          1843: {
        !          1844:   rtx label;
        !          1845: 
        !          1846:   if (conditional)
        !          1847:     {
        !          1848:       if (GET_CODE (operands[0]) != IF_THEN_ELSE)
        !          1849:        return 0;
        !          1850: 
        !          1851:       if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF)
        !          1852:        label = XEXP (XEXP (operands[0], 1), 0);
        !          1853:       else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF)
        !          1854:        label = XEXP (XEXP (operands[0], 2), 0);
        !          1855:       else return 0;
        !          1856:     }
        !          1857:   else
        !          1858:     {
        !          1859:       label = operands[0];
        !          1860:     }
        !          1861: 
        !          1862:   if (LABEL_NUSES (label) == 1)
        !          1863:     {
        !          1864:       rtx prev = PREV_INSN (label);
        !          1865:       while (prev && GET_CODE (prev) == NOTE)
        !          1866:        prev = PREV_INSN (prev);
        !          1867:       if (prev == 0
        !          1868:          || GET_CODE (prev) == BARRIER)
        !          1869:        {
        !          1870:          rtx head = next_real_insn_no_labels (label);
        !          1871: 
        !          1872:          if (head
        !          1873:              && ! INSN_DELETED_P (head)
        !          1874:              && GET_CODE (head) == INSN
        !          1875:              && GET_CODE (PATTERN (head)) == SET
        !          1876:              && strict_single_insn_op_p (SET_SRC (PATTERN (head)),
        !          1877:                                          GET_MODE (SET_DEST (PATTERN (head))))
        !          1878:              && strict_single_insn_op_p (SET_DEST (PATTERN (head)),
        !          1879:                                          GET_MODE (SET_DEST (PATTERN (head)))))
        !          1880:            {
        !          1881:              if (conditional == 2)
        !          1882:                return (GET_CODE (operands[1]) != PC
        !          1883:                        && safe_insn_src_p (operands[2], VOIDmode)
        !          1884:                        && strict_single_insn_op_p (operands[2], VOIDmode)
        !          1885:                        && operand_clobbered_before_used_after (operands[1], label));
        !          1886:              return 1;
        !          1887:            }
        !          1888:        }
        !          1889:     }
        !          1890: 
        !          1891:   if (conditional == 1
        !          1892:       && GET_CODE (operands[1]) != PC
        !          1893:       && safe_insn_src_p (operands[2], VOIDmode)
        !          1894:       && strict_single_insn_op_p (operands[2], VOIDmode)
        !          1895:       && operand_clobbered_before_used_after (operands[1], label))
        !          1896:     return 1;
        !          1897: 
        !          1898:   return 0;
        !          1899: }
        !          1900: 

unix.superglobalmegacorp.com

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