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

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

unix.superglobalmegacorp.com

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