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

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

unix.superglobalmegacorp.com

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