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

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

unix.superglobalmegacorp.com

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