Annotation of gcc/config/sparc.c, revision 1.1.1.3

1.1       root        1: /* Subroutines for insn-output.c for Sun SPARC.
                      2:    Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
                      3:    Contributed by Michael Tiemann ([email protected])
                      4: 
                      5: This file is part of GNU CC.
                      6: 
                      7: GNU CC is free software; you can redistribute it and/or modify
                      8: it under the terms of the GNU General Public License as published by
                      9: the Free Software Foundation; either version 2, or (at your option)
                     10: any later version.
                     11: 
                     12: GNU CC is distributed in the hope that it will be useful,
                     13: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     15: GNU General Public License for more details.
                     16: 
                     17: You should have received a copy of the GNU General Public License
                     18: along with GNU CC; see the file COPYING.  If not, write to
                     19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     20: 
                     21: #include <stdio.h>
                     22: #include "config.h"
1.1.1.3 ! root       23: #include "tree.h"
1.1       root       24: #include "rtl.h"
                     25: #include "regs.h"
                     26: #include "hard-reg-set.h"
                     27: #include "real.h"
                     28: #include "insn-config.h"
                     29: #include "conditions.h"
                     30: #include "insn-flags.h"
                     31: #include "output.h"
                     32: #include "insn-attr.h"
                     33: #include "flags.h"
                     34: #include "expr.h"
                     35: #include "recog.h"
                     36: 
                     37: /* Global variables for machine-dependent things.  */
                     38: 
                     39: /* Save the operands last given to a compare for use when we
                     40:    generate a scc or bcc insn.  */
                     41: 
                     42: rtx sparc_compare_op0, sparc_compare_op1;
                     43: 
                     44: /* We may need an epilogue if we spill too many registers.
                     45:    If this is non-zero, then we branch here for the epilogue.  */
                     46: static rtx leaf_label;
                     47: 
                     48: #ifdef LEAF_REGISTERS
                     49: 
                     50: /* Vector to say how input registers are mapped to output
                     51:    registers.  FRAME_POINTER_REGNUM cannot be remapped by
                     52:    this function to eliminate it.  You must use -fomit-frame-pointer
                     53:    to get that.  */
                     54: char leaf_reg_remap[] =
                     55: { 0, 1, 2, 3, 4, 5, 6, 7,
                     56:   -1, -1, -1, -1, -1, -1, 14, -1,
                     57:   -1, -1, -1, -1, -1, -1, -1, -1,
                     58:   8, 9, 10, 11, 12, 13, -1, 15,
                     59: 
                     60:   32, 33, 34, 35, 36, 37, 38, 39,
                     61:   40, 41, 42, 43, 44, 45, 46, 47,
                     62:   48, 49, 50, 51, 52, 53, 54, 55,
                     63:   56, 57, 58, 59, 60, 61, 62, 63};
                     64: 
                     65: char leaf_reg_backmap[] =
                     66: { 0, 1, 2, 3, 4, 5, 6, 7,
                     67:   24, 25, 26, 27, 28, 29, 14, 31,
                     68:   -1, -1, -1, -1, -1, -1, -1, -1,
                     69:   -1, -1, -1, -1, -1, -1, -1, -1,
                     70: 
                     71:   32, 33, 34, 35, 36, 37, 38, 39,
                     72:   40, 41, 42, 43, 44, 45, 46, 47,
                     73:   48, 49, 50, 51, 52, 53, 54, 55,
                     74:   56, 57, 58, 59, 60, 61, 62, 63};
                     75: #endif
                     76: 
                     77: /* Global variables set by FUNCTION_PROLOGUE.  */
                     78: /* Size of frame.  Need to know this to emit return insns from
                     79:    leaf procedures.  */
                     80: int apparent_fsize;
                     81: int actual_fsize;
                     82: 
                     83: /* Name of where we pretend to think the frame pointer points.
                     84:    Normally, this is "%fp", but if we are in a leaf procedure,
                     85:    this is "%sp+something".  */
                     86: char *frame_base_name;
                     87: 
                     88: static rtx find_addr_reg ();
                     89: 
                     90: /* Return non-zero only if OP is a register of mode MODE,
                     91:    or const0_rtx.  */
                     92: int
                     93: reg_or_0_operand (op, mode)
                     94:      rtx op;
                     95:      enum machine_mode mode;
                     96: {
                     97:   if (op == const0_rtx || register_operand (op, mode))
                     98:     return 1;
                     99:   if (GET_CODE (op) == CONST_DOUBLE
                    100:       && CONST_DOUBLE_HIGH (op) == 0
                    101:       && CONST_DOUBLE_LOW (op) == 0)
                    102:     return 1;
                    103:   return 0;
                    104: }
                    105: 
                    106: /* Nonzero if OP can appear as the dest of a RESTORE insn.  */
                    107: int
                    108: restore_operand (op, mode)
                    109:      rtx op;
                    110:      enum machine_mode mode;
                    111: {
                    112:   return (GET_CODE (op) == REG && GET_MODE (op) == mode
                    113:          && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
                    114: }
                    115: 
                    116: /* PC-relative call insn on SPARC is independent of `memory_operand'.  */
                    117: 
                    118: int
                    119: call_operand (op, mode)
                    120:      rtx op;
                    121:      enum machine_mode mode;
                    122: {
                    123:   if (GET_CODE (op) != MEM)
                    124:     abort ();
                    125:   op = XEXP (op, 0);
                    126:   return (REG_P (op) || CONSTANT_P (op));
                    127: }
                    128: 
                    129: int
                    130: call_operand_address (op, mode)
                    131:      rtx op;
                    132:      enum machine_mode mode;
                    133: {
                    134:   return (REG_P (op) || CONSTANT_P (op));
                    135: }
                    136: 
                    137: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
                    138:    reference and a constant.  */
                    139: 
                    140: int
                    141: symbolic_operand (op, mode)
                    142:      register rtx op;
                    143:      enum machine_mode mode;
                    144: {
                    145:   switch (GET_CODE (op))
                    146:     {
                    147:     case SYMBOL_REF:
                    148:     case LABEL_REF:
                    149:       return 1;
                    150: 
                    151:     case CONST:
                    152:       op = XEXP (op, 0);
                    153:       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
                    154:               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
                    155:              && GET_CODE (XEXP (op, 1)) == CONST_INT);
                    156: 
                    157:       /* This clause seems to be irrelevant.  */
                    158:     case CONST_DOUBLE:
                    159:       return GET_MODE (op) == mode;
                    160: 
                    161:     default:
                    162:       return 0;
                    163:     }
                    164: }
                    165: 
                    166: /* Return truth value of statement that OP is a symbolic memory
                    167:    operand of mode MODE.  */
                    168: 
                    169: int
                    170: symbolic_memory_operand (op, mode)
                    171:      rtx op;
                    172:      enum machine_mode mode;
                    173: {
                    174:   if (GET_CODE (op) == SUBREG)
                    175:     op = SUBREG_REG (op);
                    176:   if (GET_CODE (op) != MEM)
                    177:     return 0;
                    178:   op = XEXP (op, 0);
                    179:   return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
                    180:          || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
                    181: }
                    182: 
                    183: /* Return 1 if the operand is either a register or a memory operand that is
                    184:    not symbolic.  */
                    185: 
                    186: int
                    187: reg_or_nonsymb_mem_operand (op, mode)
                    188:     register rtx op;
                    189:     enum machine_mode mode;
                    190: {
                    191:   if (register_operand (op, mode))
                    192:     return 1;
                    193: 
                    194:   if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
                    195:     return 1;
                    196: 
                    197:   return 0;
                    198: }
                    199: 
                    200: int
                    201: sparc_operand (op, mode)
                    202:      rtx op;
                    203:      enum machine_mode mode;
                    204: {
                    205:   if (register_operand (op, mode))
                    206:     return 1;
                    207:   if (GET_CODE (op) == CONST_INT)
                    208:     return SMALL_INT (op);
                    209:   if (GET_MODE (op) != mode)
                    210:     return 0;
                    211:   if (GET_CODE (op) == SUBREG)
                    212:     op = SUBREG_REG (op);
                    213:   if (GET_CODE (op) != MEM)
                    214:     return 0;
                    215: 
                    216:   op = XEXP (op, 0);
                    217:   if (GET_CODE (op) == LO_SUM)
                    218:     return (GET_CODE (XEXP (op, 0)) == REG
                    219:            && symbolic_operand (XEXP (op, 1), Pmode));
                    220:   return memory_address_p (mode, op);
                    221: }
                    222: 
                    223: int
                    224: move_operand (op, mode)
                    225:      rtx op;
                    226:      enum machine_mode mode;
                    227: {
                    228:   if (mode == DImode && arith_double_operand (op, mode))
                    229:     return 1;
                    230:   if (register_operand (op, mode))
                    231:     return 1;
                    232:   if (GET_CODE (op) == CONST_INT)
                    233:     return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0);
                    234: 
                    235:   if (GET_MODE (op) != mode)
                    236:     return 0;
                    237:   if (GET_CODE (op) == SUBREG)
                    238:     op = SUBREG_REG (op);
                    239:   if (GET_CODE (op) != MEM)
                    240:     return 0;
                    241:   op = XEXP (op, 0);
                    242:   if (GET_CODE (op) == LO_SUM)
                    243:     return (register_operand (XEXP (op, 0), Pmode)
                    244:            && CONSTANT_P (XEXP (op, 1)));
                    245:   return memory_address_p (mode, op);
                    246: }
                    247: 
                    248: int
                    249: move_pic_label (op, mode)
                    250:      rtx op;
                    251:      enum machine_mode mode;
                    252: {
                    253:   /* Special case for PIC.  */
                    254:   if (flag_pic && GET_CODE (op) == LABEL_REF)
                    255:     return 1;
                    256:   return 0;
                    257: }
                    258: 
                    259: /* The rtx for the global offset table which is a special form
                    260:    that *is* a position independent symbolic constant.  */
                    261: rtx pic_pc_rtx;
                    262: 
                    263: /* Ensure that we are not using patterns that are not OK with PIC.  */
                    264: 
                    265: int
                    266: check_pic (i)
                    267:      int i;
                    268: {
                    269:   switch (flag_pic)
                    270:     {
                    271:     case 1:
                    272:       if (GET_CODE (recog_operand[i]) == SYMBOL_REF
                    273:          || (GET_CODE (recog_operand[i]) == CONST
                    274:              && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
                    275:        abort ();
                    276:     case 2:
                    277:     default:
                    278:       return 1;
                    279:     }
                    280: }
                    281: 
                    282: /* Return true if X is an address which needs a temporary register when 
                    283:    reloaded while generating PIC code.  */
                    284: 
                    285: int
                    286: pic_address_needs_scratch (x)
                    287:      rtx x;
                    288: {
                    289:   /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
                    290:   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
                    291:       && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
                    292:       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
                    293:       && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
                    294:     return 1;
                    295: 
                    296:   return 0;
                    297: }
                    298: 
                    299: int
                    300: memop (op, mode)
                    301:      rtx op;
                    302:      enum machine_mode mode;
                    303: {
                    304:   if (GET_CODE (op) == MEM)
                    305:     return (mode == VOIDmode || mode == GET_MODE (op));
                    306:   return 0;
                    307: }
                    308: 
                    309: /* Return truth value of whether OP is EQ or NE.  */
                    310: 
                    311: int
                    312: eq_or_neq (op, mode)
                    313:      rtx op;
                    314:      enum machine_mode mode;
                    315: {
                    316:   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
                    317: }
                    318: 
                    319: /* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
                    320:    or LTU for non-floating-point.  We handle those specially.  */
                    321: 
                    322: int
                    323: normal_comp_operator (op, mode)
                    324:      rtx op;
                    325:      enum machine_mode mode;
                    326: {
                    327:   enum rtx_code code = GET_CODE (op);
                    328: 
                    329:   if (GET_RTX_CLASS (code) != '<')
                    330:     return 0;
                    331: 
1.1.1.3 ! root      332:   if (GET_MODE (XEXP (op, 0)) == CCFPmode
        !           333:       || GET_MODE (XEXP (op, 0)) == CCFPEmode)
1.1       root      334:     return 1;
                    335: 
                    336:   return (code != NE && code != EQ && code != GEU && code != LTU);
                    337: }
                    338: 
                    339: /* Return 1 if this is a comparison operator.  This allows the use of
                    340:    MATCH_OPERATOR to recognize all the branch insns.  */
                    341: 
                    342: int
                    343: noov_compare_op (op, mode)
                    344:     register rtx op;
                    345:     enum machine_mode mode;
                    346: {
                    347:   enum rtx_code code = GET_CODE (op);
                    348: 
                    349:   if (GET_RTX_CLASS (code) != '<')
                    350:     return 0;
                    351: 
                    352:   if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode)
                    353:     /* These are the only branches which work with CC_NOOVmode.  */
                    354:     return (code == EQ || code == NE || code == GE || code == LT);
                    355:   return 1;
                    356: }
                    357: 
                    358: /* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation.  */
                    359: 
                    360: int
                    361: extend_op (op, mode)
                    362:      rtx op;
                    363:      enum machine_mode mode;
                    364: {
                    365:   return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
                    366: }
                    367: 
                    368: /* Return nonzero if OP is an operator of mode MODE which can set
                    369:    the condition codes explicitly.  We do not include PLUS and MINUS
                    370:    because these require CC_NOOVmode, which we handle explicitly.  */
                    371: 
                    372: int
                    373: cc_arithop (op, mode)
                    374:      rtx op;
                    375:      enum machine_mode mode;
                    376: {
                    377:   if (GET_CODE (op) == AND
                    378:       || GET_CODE (op) == IOR
                    379:       || GET_CODE (op) == XOR)
                    380:     return 1;
                    381: 
                    382:   return 0;
                    383: }
                    384: 
                    385: /* Return nonzero if OP is an operator of mode MODE which can bitwise
                    386:    complement its second operand and set the condition codes explicitly.  */
                    387: 
                    388: int
                    389: cc_arithopn (op, mode)
                    390:      rtx op;
                    391:      enum machine_mode mode;
                    392: {
                    393:   /* XOR is not here because combine canonicalizes (xor (not ...) ...)
                    394:      and (xor ... (not ...)) to (not (xor ...)).   */
                    395:   return (GET_CODE (op) == AND
                    396:          || GET_CODE (op) == IOR);
                    397: }
                    398: 
                    399: /* Return truth value of whether OP can be used as an operands in a three
                    400:    address arithmetic insn (such as add %o1,7,%l2) of mode MODE.  */
                    401: 
                    402: int
                    403: arith_operand (op, mode)
                    404:      rtx op;
                    405:      enum machine_mode mode;
                    406: {
                    407:   return (register_operand (op, mode)
                    408:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
                    409: }
                    410: 
                    411: /* Return truth value of whether OP is a register or a CONST_DOUBLE.  */
                    412: 
                    413: int
                    414: arith_double_operand (op, mode)
                    415:      rtx op;
                    416:      enum machine_mode mode;
                    417: {
                    418:   return (register_operand (op, mode)
                    419:          || (GET_CODE (op) == CONST_DOUBLE
                    420:              && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
                    421:              && (unsigned) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
                    422:              && ((CONST_DOUBLE_HIGH (op) == -1
                    423:                   && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
                    424:                  || (CONST_DOUBLE_HIGH (op) == 0
                    425:                      && (CONST_DOUBLE_LOW (op) & 0x1000) == 0)))
                    426:          || (GET_CODE (op) == CONST_INT
                    427:              && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
                    428:              && (unsigned) (INTVAL (op) + 0x1000) < 0x2000));
                    429: }
                    430: 
                    431: /* Return truth value of whether OP is a integer which fits the
                    432:    range constraining immediate operands in three-address insns.  */
                    433: 
                    434: int
                    435: small_int (op, mode)
                    436:      rtx op;
                    437:      enum machine_mode mode;
                    438: {
                    439:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
                    440: }
                    441: 
                    442: /* Return truth value of statement that OP is a call-clobbered register.  */
                    443: int
                    444: clobbered_register (op, mode)
                    445:      rtx op;
                    446:      enum machine_mode mode;
                    447: {
                    448:   return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
                    449: }
                    450: 
                    451: /* X and Y are two things to compare using CODE.  Emit the compare insn and
                    452:    return the rtx for register 0 in the proper mode.  */
                    453: 
                    454: rtx
                    455: gen_compare_reg (code, x, y)
                    456:      enum rtx_code code;
                    457:      rtx x, y;
                    458: {
                    459:   enum machine_mode mode = SELECT_CC_MODE (code, x);
                    460:   rtx cc_reg = gen_rtx (REG, mode, 0);
                    461: 
                    462:   emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
                    463:                      gen_rtx (COMPARE, mode, x, y)));
                    464: 
                    465:   return cc_reg;
                    466: }
                    467: 
                    468: /* Return nonzero if a return peephole merging return with
                    469:    setting of output register is ok.  */
                    470: int
                    471: leaf_return_peephole_ok ()
                    472: {
                    473:   return (actual_fsize == 0);
                    474: }
                    475: 
                    476: /* Return nonzero if TRIAL can go into the function epilogue's
                    477:    delay slot.  SLOT is the slot we are trying to fill.  */
                    478: 
                    479: int
                    480: eligible_for_epilogue_delay (trial, slot)
                    481:      rtx trial;
                    482:      int slot;
                    483: {
                    484:   static char *this_function_name;
                    485:   rtx pat, src;
                    486: 
                    487:   if (slot >= 1)
                    488:     return 0;
                    489:   if (GET_CODE (trial) != INSN
                    490:       || GET_CODE (PATTERN (trial)) != SET)
                    491:     return 0;
                    492:   if (get_attr_length (trial) != 1)
                    493:     return 0;
                    494: 
1.1.1.3 ! root      495:   /* In the case of a true leaf function, anything can go into the delay slot.
        !           496:      A delay slot only exists however if the frame size is zero, otherwise
        !           497:      we will put an insn to adjust the stack after the return.  */
1.1       root      498:   if (leaf_function)
                    499:     {
                    500:       if (leaf_return_peephole_ok ())
                    501:        return (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_TRUE);
                    502:       return 0;
                    503:     }
                    504: 
                    505:   /* Otherwise, only operations which can be done in tandem with
                    506:      a `restore' insn can go into the delay slot.  */
                    507:   pat = PATTERN (trial);
                    508:   if (GET_CODE (SET_DEST (pat)) != REG
                    509:       || REGNO (SET_DEST (pat)) == 0
1.1.1.3 ! root      510:       || REGNO (SET_DEST (pat)) >= 32
        !           511:       || REGNO (SET_DEST (pat)) < 24)
1.1       root      512:     return 0;
1.1.1.3 ! root      513: 
1.1       root      514:   src = SET_SRC (pat);
                    515:   if (arith_operand (src, GET_MODE (src)))
                    516:     return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
                    517:   if (arith_double_operand (src, GET_MODE (src)))
                    518:     return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
                    519:   if (GET_CODE (src) == PLUS)
                    520:     {
                    521:       if (register_operand (XEXP (src, 0), SImode)
                    522:          && arith_operand (XEXP (src, 1), SImode))
                    523:        return 1;
                    524:       if (register_operand (XEXP (src, 1), SImode)
                    525:          && arith_operand (XEXP (src, 0), SImode))
                    526:        return 1;
                    527:       if (register_operand (XEXP (src, 0), DImode)
                    528:          && arith_double_operand (XEXP (src, 1), DImode))
                    529:        return 1;
                    530:       if (register_operand (XEXP (src, 1), DImode)
                    531:          && arith_double_operand (XEXP (src, 0), DImode))
                    532:        return 1;
                    533:     }
                    534:   if (GET_CODE (src) == MINUS
                    535:       && register_operand (XEXP (src, 0), SImode)
                    536:       && small_int (XEXP (src, 1), VOIDmode))
                    537:     return 1;
                    538:   if (GET_CODE (src) == MINUS
                    539:       && register_operand (XEXP (src, 0), DImode)
                    540:       && !register_operand (XEXP (src, 1), DImode)
                    541:       && arith_double_operand (XEXP (src, 1), DImode))
                    542:     return 1;
                    543:   return 0;
                    544: }
                    545: 
                    546: int
                    547: short_branch (uid1, uid2)
                    548:      int uid1, uid2;
                    549: {
                    550:   unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2];
                    551:   if (delta + 1024 < 2048)
                    552:     return 1;
                    553:   /* warning ("long branch, distance %d", delta); */
                    554:   return 0;
                    555: }
                    556: 
                    557: /* Return non-zero if REG is not used after INSN.
                    558:    We assume REG is a reload reg, and therefore does
                    559:    not live past labels or calls or jumps.  */
                    560: int
                    561: reg_unused_after (reg, insn)
                    562:      rtx reg;
                    563:      rtx insn;
                    564: {
                    565:   enum rtx_code code, prev_code = UNKNOWN;
                    566: 
                    567:   while (insn = NEXT_INSN (insn))
                    568:     {
                    569:       if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)])
                    570:        return 1;
                    571: 
                    572:       code = GET_CODE (insn);
                    573:       if (GET_CODE (insn) == CODE_LABEL)
                    574:        return 1;
                    575: 
                    576:       if (GET_RTX_CLASS (code) == 'i')
                    577:        {
                    578:          rtx set = single_set (insn);
                    579:          int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
                    580:          if (set && in_src)
                    581:            return 0;
                    582:          if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
                    583:            return 1;
                    584:          if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
                    585:            return 0;
                    586:        }
                    587:       prev_code = code;
                    588:     }
                    589:   return 1;
                    590: }
                    591: 
                    592: /* Legitimize PIC addresses.  If the address is already position-independent,
                    593:    we return ORIG.  Newly generated position-independent addresses go into a
                    594:    reg.  This is REG if non zero, otherwise we allocate register(s) as
                    595:    necessary.  If this is called during reload, and we need a second temp
                    596:    register, then we use SCRATCH, which is provided via the
                    597:    SECONDARY_INPUT_RELOAD_CLASS mechanism.  */
                    598: 
                    599: rtx
                    600: legitimize_pic_address (orig, mode, reg, scratch)
                    601:      rtx orig;
                    602:      enum machine_mode mode;
                    603:      rtx reg, scratch;
                    604: {
                    605:   if (GET_CODE (orig) == SYMBOL_REF)
                    606:     {
                    607:       rtx pic_ref, address;
                    608:       rtx insn;
                    609: 
                    610:       if (reg == 0)
                    611:        {
1.1.1.2   root      612:          if (reload_in_progress || reload_completed)
1.1       root      613:            abort ();
                    614:          else
                    615:            reg = gen_reg_rtx (Pmode);
                    616:        }
                    617: 
                    618:       if (flag_pic == 2)
                    619:        {
                    620:          /* If not during reload, allocate another temp reg here for loading
                    621:             in the address, so that these instructions can be optimized
                    622:             properly.  */
1.1.1.2   root      623:          rtx temp_reg = ((reload_in_progress || reload_completed)
                    624:                          ? reg : gen_reg_rtx (Pmode));
1.1       root      625: 
1.1.1.2   root      626:          /* Must put the SYMBOL_REF inside an UNSPEC here so that cse
                    627:             won't get confused into thinking that these two instructions
                    628:             are loading in the true address of the symbol.  If in the
                    629:             future a PIC rtx exists, that should be used instead.  */
1.1       root      630:          emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
1.1.1.2   root      631:                              gen_rtx (HIGH, Pmode,
                    632:                                       gen_rtx (UNSPEC, Pmode,
                    633:                                                gen_rtvec (1, orig),
                    634:                                                0))));
1.1       root      635:          emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
1.1.1.2   root      636:                              gen_rtx (LO_SUM, Pmode, temp_reg,
                    637:                                       gen_rtx (UNSPEC, Pmode,
                    638:                                                gen_rtvec (1, orig),
                    639:                                                0))));
1.1       root      640:          address = temp_reg;
                    641:        }
                    642:       else
                    643:        address = orig;
                    644: 
                    645:       pic_ref = gen_rtx (MEM, Pmode,
                    646:                         gen_rtx (PLUS, Pmode,
                    647:                                  pic_offset_table_rtx, address));
                    648:       current_function_uses_pic_offset_table = 1;
                    649:       RTX_UNCHANGING_P (pic_ref) = 1;
                    650:       insn = emit_move_insn (reg, pic_ref);
                    651:       /* Put a REG_EQUAL note on this insn, so that it can be optimized
                    652:         by loop.  */
                    653:       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig,
                    654:                                  REG_NOTES (insn));
                    655:       return reg;
                    656:     }
                    657:   else if (GET_CODE (orig) == CONST)
                    658:     {
                    659:       rtx base, offset;
                    660: 
                    661:       if (GET_CODE (XEXP (orig, 0)) == PLUS
                    662:          && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
                    663:        return orig;
                    664: 
                    665:       if (reg == 0)
                    666:        {
1.1.1.2   root      667:          if (reload_in_progress || reload_completed)
1.1       root      668:            abort ();
                    669:          else
                    670:            reg = gen_reg_rtx (Pmode);
                    671:        }
                    672: 
                    673:       if (GET_CODE (XEXP (orig, 0)) == PLUS)
                    674:        {
                    675:          base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode,
                    676:                                         reg, 0);
                    677:          offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
                    678:                                         base == reg ? 0 : reg, 0);
                    679:        }
                    680:       else
                    681:        abort ();
                    682: 
                    683:       if (GET_CODE (offset) == CONST_INT)
                    684:        {
                    685:          if (SMALL_INT (offset))
                    686:            return plus_constant_for_output (base, INTVAL (offset));
1.1.1.2   root      687:          else if (! reload_in_progress && ! reload_completed)
1.1       root      688:            offset = force_reg (Pmode, offset);
                    689:          /* We can't create any new registers during reload, so use the
                    690:             SCRATCH reg provided by the reload_insi pattern.  */
                    691:          else if (scratch)
                    692:            {
                    693:              emit_move_insn (scratch, offset);
                    694:              offset = scratch;
                    695:            }
                    696:          else
                    697:            /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS
                    698:               macro needs to be adjusted so that a scratch reg is provided
                    699:               for this address.  */
                    700:            abort ();
                    701:        }
                    702:       return gen_rtx (PLUS, Pmode, base, offset);
                    703:     }
                    704:   else if (GET_CODE (orig) == LABEL_REF)
                    705:     current_function_uses_pic_offset_table = 1;
                    706: 
                    707:   return orig;
                    708: }
                    709: 
                    710: /* Set up PIC-specific rtl.  This should not cause any insns
                    711:    to be emitted.  */
                    712: 
                    713: void
                    714: initialize_pic ()
                    715: {
                    716: }
                    717: 
                    718: /* Emit special PIC prologues and epilogues.  */
                    719: 
                    720: void
                    721: finalize_pic ()
                    722: {
                    723:   /* The table we use to reference PIC data.  */
                    724:   rtx global_offset_table;
                    725:   /* Labels to get the PC in the prologue of this function.  */
                    726:   rtx l1, l2;
                    727:   rtx seq;
                    728:   int orig_flag_pic = flag_pic;
                    729: 
                    730:   if (current_function_uses_pic_offset_table == 0)
                    731:     return;
                    732: 
                    733:   if (! flag_pic)
                    734:     abort ();
                    735: 
                    736:   flag_pic = 0;
                    737:   l1 = gen_label_rtx ();
                    738:   l2 = gen_label_rtx ();
                    739: 
                    740:   start_sequence ();
                    741: 
                    742:   emit_label (l1);
                    743:   /* Note that we pun calls and jumps here!  */
                    744:   emit_jump_insn (gen_rtx (PARALLEL, VOIDmode,
                    745:                          gen_rtvec (2,
                    746:                                     gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)),
                    747:                                     gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2)))));
                    748:   emit_label (l2);
                    749: 
                    750:   /* Initialize every time through, since we can't easily
                    751:      know this to be permanent.  */
                    752:   global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "*__GLOBAL_OFFSET_TABLE_");
                    753:   pic_pc_rtx = gen_rtx (CONST, Pmode,
                    754:                        gen_rtx (MINUS, Pmode,
                    755:                                 global_offset_table,
                    756:                                 gen_rtx (CONST, Pmode,
                    757:                                          gen_rtx (MINUS, Pmode,
                    758:                                                   gen_rtx (LABEL_REF, VOIDmode, l1),
                    759:                                                   pc_rtx))));
                    760: 
                    761:   emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
                    762:                      gen_rtx (HIGH, Pmode, pic_pc_rtx)));
                    763:   emit_insn (gen_rtx (SET, VOIDmode,
                    764:                      pic_offset_table_rtx,
                    765:                      gen_rtx (LO_SUM, Pmode,
                    766:                               pic_offset_table_rtx, pic_pc_rtx)));
                    767:   emit_insn (gen_rtx (SET, VOIDmode,
                    768:                      pic_offset_table_rtx,
                    769:                      gen_rtx (PLUS, Pmode,
                    770:                               pic_offset_table_rtx, gen_rtx (REG, Pmode, 15))));
                    771:   /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */
                    772:   LABEL_PRESERVE_P (l1) = 1;
                    773:   LABEL_PRESERVE_P (l2) = 1;
                    774:   flag_pic = orig_flag_pic;
                    775: 
                    776:   seq = gen_sequence ();
                    777:   end_sequence ();
                    778:   emit_insn_after (seq, get_insns ());
                    779: 
                    780:   /* Need to emit this whether or not we obey regdecls,
                    781:      since setjmp/longjmp can cause life info to screw up.  */
                    782:   emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
                    783: }
                    784: 
                    785: /* For the SPARC, REG and REG+CONST is cost 0, REG+REG is cost 1,
                    786:    and addresses involving symbolic constants are cost 2.
                    787: 
                    788:    We make REG+REG slightly more expensive because it might keep
                    789:    a register live for longer than we might like.
                    790: 
                    791:    PIC addresses are very expensive.
                    792: 
                    793:    It is no coincidence that this has the same structure
                    794:    as GO_IF_LEGITIMATE_ADDRESS.  */
                    795: int
                    796: sparc_address_cost (X)
                    797:      rtx X;
                    798: {
                    799: #if 0
                    800:   /* Handled before calling here.  */
                    801:   if (GET_CODE (X) == REG)
                    802:     { return 1; }
                    803: #endif
                    804:   if (GET_CODE (X) == PLUS)
                    805:     {
                    806:       if (GET_CODE (XEXP (X, 0)) == REG
                    807:          && GET_CODE (XEXP (X, 1)) == REG)
                    808:        return 2;
                    809:       return 1;
                    810:     }
                    811:   else if (GET_CODE (X) == LO_SUM)
                    812:     return 1;
                    813:   else if (GET_CODE (X) == HIGH)
                    814:     return 2;
                    815:   return 4;
                    816: }
                    817: 
                    818: /* Emit insns to move operands[1] into operands[0].
                    819: 
                    820:    Return 1 if we have written out everything that needs to be done to
                    821:    do the move.  Otherwise, return 0 and the caller will emit the move
                    822:    normally.
                    823: 
                    824:    SCRATCH_REG if non zero can be used as a scratch register for the move
                    825:    operation.  It is provided by a SECONDARY_RELOAD_* macro if needed.  */
                    826: 
                    827: int
                    828: emit_move_sequence (operands, mode, scratch_reg)
                    829:      rtx *operands;
                    830:      enum machine_mode mode;
                    831:      rtx scratch_reg;
                    832: {
                    833:   register rtx operand0 = operands[0];
                    834:   register rtx operand1 = operands[1];
                    835: 
                    836:   /* Handle most common case first: storing into a register.  */
                    837:   if (register_operand (operand0, mode))
                    838:     {
                    839:       if (register_operand (operand1, mode)
                    840:          || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
                    841:          || (GET_CODE (operand1) == CONST_DOUBLE
                    842:              && arith_double_operand (operand1, DImode))
                    843:          || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode)
                    844:          /* Only `general_operands' can come here, so MEM is ok.  */
                    845:          || GET_CODE (operand1) == MEM)
                    846:        {
                    847:          /* Run this case quickly.  */
                    848:          emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
                    849:          return 1;
                    850:        }
                    851:     }
                    852:   else if (GET_CODE (operand0) == MEM)
                    853:     {
                    854:       if (register_operand (operand1, mode) || operand1 == const0_rtx)
                    855:        {
                    856:          /* Run this case quickly.  */
                    857:          emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
                    858:          return 1;
                    859:        }
                    860:       if (! reload_in_progress)
                    861:        {
                    862:          operands[0] = validize_mem (operand0);
                    863:          operands[1] = operand1 = force_reg (mode, operand1);
                    864:        }
                    865:     }
                    866: 
                    867:   /* Simplify the source if we need to.  Must handle DImode HIGH operators
                    868:      here because such a move needs a clobber added.  */
                    869:   if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
                    870:       || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode))
                    871:     {
                    872:       if (flag_pic && symbolic_operand (operand1, mode))
                    873:        {
                    874:          rtx temp_reg = reload_in_progress ? operand0 : 0;
                    875: 
                    876:          operands[1] = legitimize_pic_address (operand1, mode, temp_reg,
                    877:                                                scratch_reg);
                    878:        }
                    879:       else if (GET_CODE (operand1) == CONST_INT
                    880:               ? (! SMALL_INT (operand1)
                    881:                  && (INTVAL (operand1) & 0x3ff) != 0)
                    882:               : (GET_CODE (operand1) == CONST_DOUBLE
                    883:                  ? ! arith_double_operand (operand1, DImode)
                    884:                  : 1))
                    885:        {
                    886:          /* For DImode values, temp must be operand0 because of the way
                    887:             HI and LO_SUM work.  The LO_SUM operator only copies half of
                    888:             the LSW from the dest of the HI operator.  If the LO_SUM dest is
                    889:             not the same as the HI dest, then the MSW of the LO_SUM dest will
                    890:             never be set.
                    891: 
                    892:             ??? The real problem here is that the ...(HI:DImode pattern emits
                    893:             multiple instructions, and the ...(LO_SUM:DImode pattern emits
                    894:             one instruction.  This fails, because the compiler assumes that
                    895:             LO_SUM copies all bits of the first operand to its dest.  Better
                    896:             would be to have the HI pattern emit one instruction and the
                    897:             LO_SUM pattern multiple instructions.  Even better would be
                    898:             to use four rtl insns.  */
                    899:          rtx temp = ((reload_in_progress || mode == DImode)
                    900:                      ? operand0 : gen_reg_rtx (mode));
                    901: 
                    902:          emit_insn (gen_rtx (SET, VOIDmode, temp,
                    903:                              gen_rtx (HIGH, mode, operand1)));
                    904:          operands[1] = gen_rtx (LO_SUM, mode, temp, operand1);
                    905:        }
                    906:     }
                    907: 
                    908:   if (GET_CODE (operand1) == LABEL_REF && flag_pic)
                    909:     {
                    910:       /* The procedure for doing this involves using a call instruction to
                    911:         get the pc into o7.  We need to indicate this explicitly because
                    912:         the tablejump pattern assumes that it can use this value also.  */
                    913:       emit_insn (gen_rtx (PARALLEL, VOIDmode,
                    914:                          gen_rtvec (2,
                    915:                                     gen_rtx (SET, VOIDmode, operand0,
                    916:                                              operand1),
                    917:                                     gen_rtx (SET, VOIDmode,
                    918:                                              gen_rtx (REG, mode, 15),
                    919:                                              pc_rtx))));
                    920:       return 1;
                    921:     }
                    922: 
                    923:   /* Now have insn-emit do whatever it normally does.  */
                    924:   return 0;
                    925: }
                    926: 
                    927: /* Return the best assembler insn template
                    928:    for moving operands[1] into operands[0] as a fullword.  */
                    929: 
                    930: char *
                    931: singlemove_string (operands)
                    932:      rtx *operands;
                    933: {
                    934:   if (GET_CODE (operands[0]) == MEM)
                    935:     {
                    936:       if (GET_CODE (operands[1]) != MEM)
                    937:        return "st %r1,%0";
                    938:       else
                    939:        abort ();
                    940:     }
1.1.1.3 ! root      941:   else if (GET_CODE (operands[1]) == MEM)
1.1       root      942:     return "ld %1,%0";
1.1.1.3 ! root      943:   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
        !           944:     {
        !           945:       int i;
        !           946:       union real_extract u;
        !           947:       union float_extract { float f; int i; } v;
        !           948: 
        !           949:       /* Must be SFmode, otherwise this doesn't make sense.  */
        !           950:       if (GET_MODE (operands[1]) != SFmode)
        !           951:        abort ();
        !           952: 
        !           953:       bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u);
        !           954:       v.f = REAL_VALUE_TRUNCATE (SFmode, u.d);
        !           955:       i = v.i;
        !           956: 
        !           957:       operands[1] = gen_rtx (CONST_INT, VOIDmode, i);
        !           958: 
        !           959:       if (CONST_OK_FOR_LETTER_P (i, 'I'))
        !           960:        return "mov %1,%0";
        !           961:       else if ((i & 0x000003FF) != 0)
        !           962:        return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
        !           963:       else
        !           964:        return "sethi %%hi(%a1),%0";
        !           965:     }
        !           966:   else if (GET_CODE (operands[1]) == CONST_INT
        !           967:           && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
1.1       root      968:     {
                    969:       int i = INTVAL (operands[1]);
                    970: 
1.1.1.3 ! root      971:       /* If all low order 10 bits are clear, then we only need a single
1.1       root      972:         sethi insn to load the constant.  */
1.1.1.3 ! root      973:       if ((i & 0x000003FF) != 0)
1.1       root      974:        return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
                    975:       else
                    976:        return "sethi %%hi(%a1),%0";
                    977:     }
1.1.1.3 ! root      978:   /* Operand 1 must be a register, or a 'I' type CONST_INT.  */
1.1       root      979:   return "mov %1,%0";
                    980: }
                    981: 
1.1.1.3 ! root      982: /* Return non-zero if it is OK to assume that the given memory operand is
        !           983:    aligned at least to a 8-byte boundary.  This should only be called
        !           984:    for memory accesses whose size is 8 bytes or larger.  */
        !           985: 
        !           986: static int
        !           987: mem_aligned_8 (mem)
        !           988:      register rtx mem;
        !           989: {
        !           990:   register rtx addr;
        !           991:   register rtx base;
        !           992:   register rtx offset;
        !           993: 
        !           994:   if (GET_CODE (mem) != MEM)
        !           995:     abort ();  /* It's gotta be a MEM! */
        !           996: 
        !           997:   addr = XEXP (mem, 0);
        !           998: 
        !           999: #if 1
        !          1000:   /* Now that all misaligned double parms are copied on function entry,
        !          1001:      we can assume any 64-bit object is 64-bit aligned.  */
        !          1002: 
        !          1003:   /* See what register we use in the address.  */
        !          1004:   base = 0;
        !          1005:   if (GET_CODE (addr) == PLUS)
        !          1006:     {
        !          1007:       if (GET_CODE (XEXP (addr, 0)) == REG
        !          1008:          && GET_CODE (XEXP (addr, 1)) == CONST_INT)
        !          1009:        {
        !          1010:          base = XEXP (addr, 0);
        !          1011:          offset = XEXP (addr, 1);
        !          1012:        }
        !          1013:     }
        !          1014:   else if (GET_CODE (addr) == REG)
        !          1015:     {
        !          1016:       base = addr;
        !          1017:       offset = const0_rtx;
        !          1018:     }
        !          1019: 
        !          1020:   /* If it's the stack or frame pointer, check offset alignment.
        !          1021:      We can have improper aligment in the function entry code.  */
        !          1022:   if (base
        !          1023:       && (REGNO (base) == FRAME_POINTER_REGNUM
        !          1024:          || REGNO (base) == STACK_POINTER_REGNUM))
        !          1025:     {
        !          1026:       if ((INTVAL (offset) & 0x7) == 0)
        !          1027:        return 1;
        !          1028:     }
        !          1029:   else
        !          1030:     /* Anything else, we know is properly aligned.  */
        !          1031:     return 1;
        !          1032: #else
        !          1033:   /* If the operand is known to have been allocated in static storage, then
        !          1034:      it must be aligned.  */
        !          1035: 
        !          1036:   if (CONSTANT_P (addr) || GET_CODE (addr) == LO_SUM)
        !          1037:     return 1;
        !          1038: 
        !          1039:   base = 0;
        !          1040:   if (GET_CODE (addr) == PLUS)
        !          1041:     {
        !          1042:       if (GET_CODE (XEXP (addr, 0)) == REG
        !          1043:           && GET_CODE (XEXP (addr, 1)) == CONST_INT)
        !          1044:         {
        !          1045:           base = XEXP (addr, 0);
        !          1046:           offset = XEXP (addr, 1);
        !          1047:         }
        !          1048:     }
        !          1049:   else if (GET_CODE (addr) == REG)
        !          1050:     {
        !          1051:       base = addr;
        !          1052:       offset = const0_rtx;
        !          1053:     }
        !          1054: 
        !          1055:   /* Trust round enough offsets from the stack or frame pointer.
        !          1056:      If TARGET_HOPE_ALIGN, trust round enough offset from any register.
        !          1057:      If it is obviously unaligned, don't ever return true.  */
        !          1058:   if (base
        !          1059:       && (REGNO (base) == FRAME_POINTER_REGNUM
        !          1060:           || REGNO (base) == STACK_POINTER_REGNUM
        !          1061:          || TARGET_HOPE_ALIGN))
        !          1062:     {
        !          1063:       if ((INTVAL (offset) & 0x7) == 0)
        !          1064:        return 1;
        !          1065:     }
        !          1066:   /* Otherwise, we can assume that an access is aligned if it is to an
        !          1067:      aggregate.  Also, if TARGET_HOPE_ALIGN, then assume everything that isn't
        !          1068:      obviously unaligned is aligned.  */
        !          1069:   else if (MEM_IN_STRUCT_P (mem) || TARGET_HOPE_ALIGN)
        !          1070:     return 1;
        !          1071: #endif
        !          1072: 
        !          1073:   /* An obviously unaligned address.  */
        !          1074:   return 0;
        !          1075: }
        !          1076: 
        !          1077: enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP };
        !          1078: 
1.1       root     1079: /* Output assembler code to perform a doubleword move insn
1.1.1.3 ! root     1080:    with operands OPERANDS.  This is very similar to the following
        !          1081:    output_move_quad function.  */
1.1       root     1082: 
                   1083: char *
                   1084: output_move_double (operands)
                   1085:      rtx *operands;
                   1086: {
1.1.1.3 ! root     1087:   register rtx op0 = operands[0];
        !          1088:   register rtx op1 = operands[1];
        !          1089:   register enum optype optype0;
        !          1090:   register enum optype optype1;
1.1       root     1091:   rtx latehalf[2];
1.1.1.3 ! root     1092:   rtx addreg0 = 0;
        !          1093:   rtx addreg1 = 0;
1.1       root     1094: 
                   1095:   /* First classify both operands.  */
                   1096: 
1.1.1.3 ! root     1097:   if (REG_P (op0))
1.1       root     1098:     optype0 = REGOP;
1.1.1.3 ! root     1099:   else if (offsettable_memref_p (op0))
1.1       root     1100:     optype0 = OFFSOP;
1.1.1.3 ! root     1101:   else if (GET_CODE (op0) == MEM)
1.1       root     1102:     optype0 = MEMOP;
                   1103:   else
                   1104:     optype0 = RNDOP;
                   1105: 
1.1.1.3 ! root     1106:   if (REG_P (op1))
1.1       root     1107:     optype1 = REGOP;
1.1.1.3 ! root     1108:   else if (CONSTANT_P (op1))
1.1       root     1109:     optype1 = CNSTOP;
1.1.1.3 ! root     1110:   else if (offsettable_memref_p (op1))
1.1       root     1111:     optype1 = OFFSOP;
1.1.1.3 ! root     1112:   else if (GET_CODE (op1) == MEM)
1.1       root     1113:     optype1 = MEMOP;
                   1114:   else
                   1115:     optype1 = RNDOP;
                   1116: 
                   1117:   /* Check for the cases that the operand constraints are not
                   1118:      supposed to allow to happen.  Abort if we get one,
                   1119:      because generating code for these cases is painful.  */
                   1120: 
1.1.1.3 ! root     1121:   if (optype0 == RNDOP || optype1 == RNDOP
        !          1122:       || (optype0 == MEM && optype1 == MEM))
1.1       root     1123:     abort ();
                   1124: 
                   1125:   /* If an operand is an unoffsettable memory ref, find a register
                   1126:      we can increment temporarily to make it refer to the second word.  */
                   1127: 
                   1128:   if (optype0 == MEMOP)
1.1.1.3 ! root     1129:     addreg0 = find_addr_reg (XEXP (op0, 0));
1.1       root     1130: 
                   1131:   if (optype1 == MEMOP)
1.1.1.3 ! root     1132:     addreg1 = find_addr_reg (XEXP (op1, 0));
1.1       root     1133: 
                   1134:   /* Ok, we can do one word at a time.
1.1.1.3 ! root     1135:      Set up in LATEHALF the operands to use for the
1.1       root     1136:      high-numbered (least significant) word and in some cases alter the
                   1137:      operands in OPERANDS to be suitable for the low-numbered word.  */
                   1138: 
                   1139:   if (optype0 == REGOP)
1.1.1.3 ! root     1140:     latehalf[0] = gen_rtx (REG, SImode, REGNO (op0) + 1);
1.1       root     1141:   else if (optype0 == OFFSOP)
1.1.1.3 ! root     1142:     latehalf[0] = adj_offsettable_operand (op0, 4);
1.1       root     1143:   else
1.1.1.3 ! root     1144:     latehalf[0] = op0;
1.1       root     1145: 
                   1146:   if (optype1 == REGOP)
1.1.1.3 ! root     1147:     latehalf[1] = gen_rtx (REG, SImode, REGNO (op1) + 1);
1.1       root     1148:   else if (optype1 == OFFSOP)
1.1.1.3 ! root     1149:     latehalf[1] = adj_offsettable_operand (op1, 4);
1.1       root     1150:   else if (optype1 == CNSTOP)
1.1.1.3 ! root     1151:     split_double (op1, &operands[1], &latehalf[1]);
1.1       root     1152:   else
1.1.1.3 ! root     1153:     latehalf[1] = op1;
1.1       root     1154: 
1.1.1.3 ! root     1155:   /* Easy case: try moving both words at once.  Check for moving between
        !          1156:      an even/odd register pair and a memory location.  */
1.1       root     1157:   if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP
1.1.1.3 ! root     1158:        && (REGNO (op0) & 1) == 0)
1.1       root     1159:       || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP
1.1.1.3 ! root     1160:          && (REGNO (op1) & 1) == 0))
1.1       root     1161:     {
1.1.1.3 ! root     1162:       register rtx mem;
1.1       root     1163: 
                   1164:       if (optype0 == REGOP)
1.1.1.3 ! root     1165:        mem = op1;
1.1       root     1166:       else
1.1.1.3 ! root     1167:        mem = op0;
1.1       root     1168: 
1.1.1.3 ! root     1169:       if (mem_aligned_8 (mem))
        !          1170:        return (mem == op1 ? "ldd %1,%0" : "std %1,%0");
1.1       root     1171:     }
                   1172: 
1.1.1.3 ! root     1173:   /* If the first move would clobber the source of the second one,
        !          1174:      do them in the other order.  */
        !          1175: 
        !          1176:   /* Overlapping registers.  */
1.1       root     1177:   if (optype0 == REGOP && optype1 == REGOP
1.1.1.3 ! root     1178:       && REGNO (op0) == REGNO (latehalf[1]))
1.1       root     1179:     {
                   1180:       /* Do that word.  */
                   1181:       output_asm_insn (singlemove_string (latehalf), latehalf);
                   1182:       /* Do low-numbered word.  */
                   1183:       return singlemove_string (operands);
                   1184:     }
1.1.1.3 ! root     1185:   /* Loading into a register which overlaps a register used in the address.  */
1.1       root     1186:   else if (optype0 == REGOP && optype1 != REGOP
1.1.1.3 ! root     1187:           && reg_overlap_mentioned_p (op0, op1))
1.1       root     1188:     {
1.1.1.3 ! root     1189:       /* ??? This fails if the address is a double register address, each
        !          1190:         of which is clobbered by operand 0.  */
1.1       root     1191:       /* Do the late half first.  */
                   1192:       output_asm_insn (singlemove_string (latehalf), latehalf);
                   1193:       /* Then clobber.  */
                   1194:       return singlemove_string (operands);
                   1195:     }
                   1196: 
                   1197:   /* Normal case: do the two words, low-numbered first.  */
                   1198: 
                   1199:   output_asm_insn (singlemove_string (operands), operands);
                   1200: 
                   1201:   /* Make any unoffsettable addresses point at high-numbered word.  */
                   1202:   if (addreg0)
                   1203:     output_asm_insn ("add %0,0x4,%0", &addreg0);
                   1204:   if (addreg1)
                   1205:     output_asm_insn ("add %0,0x4,%0", &addreg1);
                   1206: 
                   1207:   /* Do that word.  */
                   1208:   output_asm_insn (singlemove_string (latehalf), latehalf);
                   1209: 
                   1210:   /* Undo the adds we just did.  */
                   1211:   if (addreg0)
                   1212:     output_asm_insn ("add %0,-0x4,%0", &addreg0);
                   1213:   if (addreg1)
                   1214:     output_asm_insn ("add %0,-0x4,%0", &addreg1);
                   1215: 
                   1216:   return "";
                   1217: }
1.1.1.3 ! root     1218: 
        !          1219: /* Output assembler code to perform a quadword move insn
        !          1220:    with operands OPERANDS.  This is very similar to the preceeding
        !          1221:    output_move_double function.  */
        !          1222: 
        !          1223: char *
        !          1224: output_move_quad (operands)
        !          1225:      rtx *operands;
        !          1226: {
        !          1227:   register rtx op0 = operands[0];
        !          1228:   register rtx op1 = operands[1];
        !          1229:   register enum optype optype0;
        !          1230:   register enum optype optype1;
        !          1231:   rtx wordpart[4][2];
        !          1232:   rtx addreg0 = 0;
        !          1233:   rtx addreg1 = 0;
        !          1234: 
        !          1235:   /* First classify both operands.  */
        !          1236: 
        !          1237:   if (REG_P (op0))
        !          1238:     optype0 = REGOP;
        !          1239:   else if (offsettable_memref_p (op0))
        !          1240:     optype0 = OFFSOP;
        !          1241:   else if (GET_CODE (op0) == MEM)
        !          1242:     optype0 = MEMOP;
        !          1243:   else
        !          1244:     optype0 = RNDOP;
        !          1245: 
        !          1246:   if (REG_P (op1))
        !          1247:     optype1 = REGOP;
        !          1248:   else if (CONSTANT_P (op1))
        !          1249:     optype1 = CNSTOP;
        !          1250:   else if (offsettable_memref_p (op1))
        !          1251:     optype1 = OFFSOP;
        !          1252:   else if (GET_CODE (op1) == MEM)
        !          1253:     optype1 = MEMOP;
        !          1254:   else
        !          1255:     optype1 = RNDOP;
        !          1256: 
        !          1257:   /* Check for the cases that the operand constraints are not
        !          1258:      supposed to allow to happen.  Abort if we get one,
        !          1259:      because generating code for these cases is painful.  */
        !          1260: 
        !          1261:   if (optype0 == RNDOP || optype1 == RNDOP
        !          1262:       || (optype0 == MEM && optype1 == MEM))
        !          1263:     abort ();
        !          1264: 
        !          1265:   /* If an operand is an unoffsettable memory ref, find a register
        !          1266:      we can increment temporarily to make it refer to the later words.  */
        !          1267: 
        !          1268:   if (optype0 == MEMOP)
        !          1269:     addreg0 = find_addr_reg (XEXP (op0, 0));
        !          1270: 
        !          1271:   if (optype1 == MEMOP)
        !          1272:     addreg1 = find_addr_reg (XEXP (op1, 0));
        !          1273: 
        !          1274:   /* Ok, we can do one word at a time.
        !          1275:      Set up in wordpart the operands to use for each word of the arguments.  */
        !          1276: 
        !          1277:   if (optype0 == REGOP)
        !          1278:     {
        !          1279:       wordpart[0][0] = gen_rtx (REG, SImode, REGNO (op0) + 0);
        !          1280:       wordpart[1][0] = gen_rtx (REG, SImode, REGNO (op0) + 1);
        !          1281:       wordpart[2][0] = gen_rtx (REG, SImode, REGNO (op0) + 2);
        !          1282:       wordpart[3][0] = gen_rtx (REG, SImode, REGNO (op0) + 3);
        !          1283:     }
        !          1284:   else if (optype0 == OFFSOP)
        !          1285:     {
        !          1286:       wordpart[0][0] = adj_offsettable_operand (op0, 0);
        !          1287:       wordpart[1][0] = adj_offsettable_operand (op0, 4);
        !          1288:       wordpart[2][0] = adj_offsettable_operand (op0, 8);
        !          1289:       wordpart[3][0] = adj_offsettable_operand (op0, 12);
        !          1290:     }
        !          1291:   else
        !          1292:     {
        !          1293:       wordpart[0][0] = op0;
        !          1294:       wordpart[1][0] = op0;
        !          1295:       wordpart[2][0] = op0;
        !          1296:       wordpart[3][0] = op0;
        !          1297:     }
        !          1298: 
        !          1299:   if (optype1 == REGOP)
        !          1300:     {
        !          1301:       wordpart[0][1] = gen_rtx (REG, SImode, REGNO (op1) + 0);
        !          1302:       wordpart[1][1] = gen_rtx (REG, SImode, REGNO (op1) + 1);
        !          1303:       wordpart[2][1] = gen_rtx (REG, SImode, REGNO (op1) + 2);
        !          1304:       wordpart[3][1] = gen_rtx (REG, SImode, REGNO (op1) + 3);
        !          1305:     }
        !          1306:   else if (optype1 == OFFSOP)
        !          1307:     {
        !          1308:       wordpart[0][1] = adj_offsettable_operand (op1, 0);
        !          1309:       wordpart[1][1] = adj_offsettable_operand (op1, 4);
        !          1310:       wordpart[2][1] = adj_offsettable_operand (op1, 8);
        !          1311:       wordpart[3][1] = adj_offsettable_operand (op1, 12);
        !          1312:     }
        !          1313:   else if (optype1 == CNSTOP)
        !          1314:     {
        !          1315:       /* This case isn't implemented yet, because there is no internal
        !          1316:         representation for quad-word constants, and there is no split_quad
        !          1317:         function.  */
        !          1318: #if 0
        !          1319:       split_quad (op1, &wordpart[0][1], &wordpart[1][1],
        !          1320:                  &wordpart[2][1], &wordpart[3][1]);
        !          1321: #else
        !          1322:       abort ();
        !          1323: #endif
        !          1324:     }
        !          1325:   else
        !          1326:     {
        !          1327:       wordpart[0][1] = op1;
        !          1328:       wordpart[1][1] = op1;
        !          1329:       wordpart[2][1] = op1;
        !          1330:       wordpart[3][1] = op1;
        !          1331:     }
        !          1332: 
        !          1333:   /* Easy case: try moving the quad as two pairs.  Check for moving between
        !          1334:      an even/odd register pair and a memory location.  */
        !          1335:   /* ??? Should also handle the case of non-offsettable addresses here.
        !          1336:      We can at least do the first pair as a ldd/std, and then do the third
        !          1337:      and fourth words individually.  */
        !          1338:   if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0)
        !          1339:       || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0))
        !          1340:     {
        !          1341:       rtx mem;
        !          1342: 
        !          1343:       if (optype0 == REGOP)
        !          1344:        mem = op1;
        !          1345:       else
        !          1346:        mem = op0;
        !          1347: 
        !          1348:       if (mem_aligned_8 (mem))
        !          1349:        {
        !          1350:          operands[2] = adj_offsettable_operand (mem, 8);
        !          1351:          if (mem == op1)
        !          1352:            return "ldd %1,%0;ldd %2,%S0";
        !          1353:          else
        !          1354:            return "std %1,%0;std %S1,%2";
        !          1355:        }
        !          1356:     }
        !          1357: 
        !          1358:   /* If the first move would clobber the source of the second one,
        !          1359:      do them in the other order.  */
        !          1360: 
        !          1361:   /* Overlapping registers.  */
        !          1362:   if (optype0 == REGOP && optype1 == REGOP
        !          1363:       && (REGNO (op0) == REGNO (wordpart[1][3])
        !          1364:          || REGNO (op0) == REGNO (wordpart[1][2])
        !          1365:          || REGNO (op0) == REGNO (wordpart[1][1])))
        !          1366:     {
        !          1367:       /* Do fourth word.  */
        !          1368:       output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
        !          1369:       /* Do the third word.  */
        !          1370:       output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
        !          1371:       /* Do the second word.  */
        !          1372:       output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
        !          1373:       /* Do lowest-numbered word.  */
        !          1374:       return singlemove_string (wordpart[0]);
        !          1375:     }
        !          1376:   /* Loading into a register which overlaps a register used in the address.  */
        !          1377:   if (optype0 == REGOP && optype1 != REGOP
        !          1378:       && reg_overlap_mentioned_p (op0, op1))
        !          1379:     {
        !          1380:       /* ??? Not implemented yet.  This is a bit complicated, because we
        !          1381:         must load which ever part overlaps the address last.  If the address
        !          1382:         is a double-reg address, then there are two parts which need to
        !          1383:         be done last, which is impossible.  We would need a scratch register
        !          1384:         in that case.  */
        !          1385:       abort ();
        !          1386:     }
        !          1387: 
        !          1388:   /* Normal case: move the four words in lowest to higest address order.  */
        !          1389: 
        !          1390:   output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
        !          1391: 
        !          1392:   /* Make any unoffsettable addresses point at the second word.  */
        !          1393:   if (addreg0)
        !          1394:     output_asm_insn ("add %0,0x4,%0", &addreg0);
        !          1395:   if (addreg1)
        !          1396:     output_asm_insn ("add %0,0x4,%0", &addreg1);
        !          1397: 
        !          1398:   /* Do the second word.  */
        !          1399:   output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
        !          1400: 
        !          1401:   /* Make any unoffsettable addresses point at the third word.  */
        !          1402:   if (addreg0)
        !          1403:     output_asm_insn ("add %0,0x4,%0", &addreg0);
        !          1404:   if (addreg1)
        !          1405:     output_asm_insn ("add %0,0x4,%0", &addreg1);
        !          1406: 
        !          1407:   /* Do the third word.  */
        !          1408:   output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
        !          1409: 
        !          1410:   /* Make any unoffsettable addresses point at the fourth word.  */
        !          1411:   if (addreg0)
        !          1412:     output_asm_insn ("add %0,0x4,%0", &addreg0);
        !          1413:   if (addreg1)
        !          1414:     output_asm_insn ("add %0,0x4,%0", &addreg1);
        !          1415: 
        !          1416:   /* Do the fourth word.  */
        !          1417:   output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
        !          1418: 
        !          1419:   /* Undo the adds we just did.  */
        !          1420:   if (addreg0)
        !          1421:     output_asm_insn ("add %0,-0xc,%0", &addreg0);
        !          1422:   if (addreg1)
        !          1423:     output_asm_insn ("add %0,-0xc,%0", &addreg1);
        !          1424: 
        !          1425:   return "";
        !          1426: }
1.1       root     1427: 
1.1.1.3 ! root     1428: /* Output assembler code to perform a doubleword move insn with operands
        !          1429:    OPERANDS, one of which must be a floating point register.  */
        !          1430: 
1.1       root     1431: char *
                   1432: output_fp_move_double (operands)
                   1433:      rtx *operands;
                   1434: {
                   1435:   rtx addr;
                   1436: 
                   1437:   if (FP_REG_P (operands[0]))
                   1438:     {
                   1439:       if (FP_REG_P (operands[1]))
                   1440:        return "fmovs %1,%0\n\tfmovs %R1,%R0";
1.1.1.3 ! root     1441:       else if (GET_CODE (operands[1]) == REG)
1.1       root     1442:        {
                   1443:          if ((REGNO (operands[1]) & 1) == 0)
                   1444:            return "std %1,[%@-8]\n\tldd [%@-8],%0";
                   1445:          else
                   1446:            return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0";
                   1447:        }
1.1.1.3 ! root     1448:       else
        !          1449:        return output_move_double (operands);
1.1       root     1450:     }
                   1451:   else if (FP_REG_P (operands[1]))
                   1452:     {
                   1453:       if (GET_CODE (operands[0]) == REG)
                   1454:        {
                   1455:          if ((REGNO (operands[0]) & 1) == 0)
                   1456:            return "std %1,[%@-8]\n\tldd [%@-8],%0";
                   1457:          else
                   1458:            return "std %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0";
                   1459:        }
1.1.1.3 ! root     1460:       else
        !          1461:        return output_move_double (operands);
1.1       root     1462:     }
                   1463:   else abort ();
                   1464: }
1.1.1.3 ! root     1465: 
        !          1466: /* Output assembler code to perform a quadword move insn with operands
        !          1467:    OPERANDS, one of which must be a floating point register.  */
        !          1468: 
        !          1469: char *
        !          1470: output_fp_move_quad (operands)
        !          1471:      rtx *operands;
        !          1472: {
        !          1473:   register rtx op0 = operands[0];
        !          1474:   register rtx op1 = operands[1];
        !          1475:   register rtx addr;
        !          1476: 
        !          1477:   if (FP_REG_P (op0))
        !          1478:     {
        !          1479:       if (FP_REG_P (op1))
        !          1480:        return "fmovs %1,%0\n\tfmovs %R1,%R0\n\tfmovs %S1,%S0\n\tfmovs %T1,%T0";
        !          1481:       if (GET_CODE (op1) == REG)
        !          1482:        {
        !          1483:          if ((REGNO (op1) & 1) == 0)
        !          1484:            return "std %1,[%@-8]\n\tldd [%@-8],%0\n\tstd %S1,[%@-8]\n\tldd [%@-8],%S0";
        !          1485:          else
        !          1486:            return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0\n\tst %T1,[%@-4]\n\tst %S1,[%@-8]\n\tldd [%@-8],%S0";
        !          1487:        }
        !          1488:       else
        !          1489:        return output_move_quad (operands);
        !          1490:     }
        !          1491:   else if (FP_REG_P (op1))
        !          1492:     {
        !          1493:       if (GET_CODE (op0) == REG)
        !          1494:        {
        !          1495:          if ((REGNO (op0) & 1) == 0)
        !          1496:            return "std %1,[%@-8]\n\tldd [%@-8],%0\n\tstd %S1,[%@-8]\n\tldd [%@-8],%S0";
        !          1497:          else
        !          1498:            return "std %S1,[%@-8]\n\tld [%@-4],%T0\n\tld [%@-8],%S0\n\tstd %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0";
        !          1499:        }
        !          1500:       else
        !          1501:        return output_move_quad (operands);
        !          1502:     }
        !          1503:   else
        !          1504:     abort ();
        !          1505: }
1.1       root     1506: 
                   1507: /* Return a REG that occurs in ADDR with coefficient 1.
                   1508:    ADDR can be effectively incremented by incrementing REG.  */
                   1509: 
                   1510: static rtx
                   1511: find_addr_reg (addr)
                   1512:      rtx addr;
                   1513: {
                   1514:   while (GET_CODE (addr) == PLUS)
                   1515:     {
                   1516:       /* We absolutely can not fudge the frame pointer here, because the
                   1517:         frame pointer must always be 8 byte aligned.  It also confuses
                   1518:         debuggers.  */
                   1519:       if (GET_CODE (XEXP (addr, 0)) == REG
                   1520:          && REGNO (XEXP (addr, 0)) != FRAME_POINTER_REGNUM)
                   1521:        addr = XEXP (addr, 0);
                   1522:       else if (GET_CODE (XEXP (addr, 1)) == REG
                   1523:               && REGNO (XEXP (addr, 1)) != FRAME_POINTER_REGNUM)
                   1524:        addr = XEXP (addr, 1);
                   1525:       else if (CONSTANT_P (XEXP (addr, 0)))
                   1526:        addr = XEXP (addr, 1);
                   1527:       else if (CONSTANT_P (XEXP (addr, 1)))
                   1528:        addr = XEXP (addr, 0);
                   1529:       else
                   1530:        abort ();
                   1531:     }
                   1532:   if (GET_CODE (addr) == REG)
                   1533:     return addr;
                   1534:   abort ();
                   1535: }
                   1536: 
                   1537: void
                   1538: output_sized_memop (opname, mode, signedp)
                   1539:      char *opname;
                   1540:      enum machine_mode mode;
                   1541:      int signedp;
                   1542: {
                   1543:   static char *ld_size_suffix_u[] = { "ub", "uh", "", "?", "d" };
                   1544:   static char *ld_size_suffix_s[] = { "sb", "sh", "", "?", "d" };
                   1545:   static char *st_size_suffix[] = { "b", "h", "", "?", "d" };
                   1546:   char **opnametab, *modename;
                   1547: 
                   1548:   if (opname[0] == 'l')
                   1549:     if (signedp)
                   1550:       opnametab = ld_size_suffix_s;
                   1551:     else
                   1552:       opnametab = ld_size_suffix_u;
                   1553:   else
                   1554:     opnametab = st_size_suffix;
                   1555:   modename = opnametab[GET_MODE_SIZE (mode) >> 1];
                   1556: 
                   1557:   fprintf (asm_out_file, "\t%s%s", opname, modename);
                   1558: }
                   1559: 
                   1560: void
                   1561: output_move_with_extension (operands)
                   1562:      rtx *operands;
                   1563: {
                   1564:   if (GET_MODE (operands[2]) == HImode)
                   1565:     output_asm_insn ("sll %2,0x10,%0", operands);
                   1566:   else if (GET_MODE (operands[2]) == QImode)
                   1567:     output_asm_insn ("sll %2,0x18,%0", operands);
                   1568:   else
                   1569:     abort ();
                   1570: }
                   1571: 
                   1572: /* Load the address specified by OPERANDS[3] into the register
                   1573:    specified by OPERANDS[0].
                   1574: 
                   1575:    OPERANDS[3] may be the result of a sum, hence it could either be:
                   1576: 
                   1577:    (1) CONST
                   1578:    (2) REG
                   1579:    (2) REG + CONST_INT
                   1580:    (3) REG + REG + CONST_INT
                   1581:    (4) REG + REG  (special case of 3).
                   1582: 
                   1583:    Note that (3) is not a legitimate address.
                   1584:    All cases are handled here.  */
                   1585: 
                   1586: void
                   1587: output_load_address (operands)
                   1588:      rtx *operands;
                   1589: {
                   1590:   rtx base, offset;
                   1591: 
                   1592:   if (CONSTANT_P (operands[3]))
                   1593:     {
                   1594:       output_asm_insn ("set %3,%0", operands);
                   1595:       return;
                   1596:     }
                   1597: 
                   1598:   if (REG_P (operands[3]))
                   1599:     {
                   1600:       if (REGNO (operands[0]) != REGNO (operands[3]))
                   1601:        output_asm_insn ("mov %3,%0", operands);
                   1602:       return;
                   1603:     }
                   1604: 
                   1605:   if (GET_CODE (operands[3]) != PLUS)
                   1606:     abort ();
                   1607: 
                   1608:   base = XEXP (operands[3], 0);
                   1609:   offset = XEXP (operands[3], 1);
                   1610: 
                   1611:   if (GET_CODE (base) == CONST_INT)
                   1612:     {
                   1613:       rtx tmp = base;
                   1614:       base = offset;
                   1615:       offset = tmp;
                   1616:     }
                   1617: 
                   1618:   if (GET_CODE (offset) != CONST_INT)
                   1619:     {
                   1620:       /* Operand is (PLUS (REG) (REG)).  */
                   1621:       base = operands[3];
                   1622:       offset = const0_rtx;
                   1623:     }
                   1624: 
                   1625:   if (REG_P (base))
                   1626:     {
                   1627:       operands[6] = base;
                   1628:       operands[7] = offset;
                   1629:       if (SMALL_INT (offset))
                   1630:        output_asm_insn ("add %6,%7,%0", operands);
                   1631:       else
                   1632:        output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
                   1633:     }
                   1634:   else if (GET_CODE (base) == PLUS)
                   1635:     {
                   1636:       operands[6] = XEXP (base, 0);
                   1637:       operands[7] = XEXP (base, 1);
                   1638:       operands[8] = offset;
                   1639: 
                   1640:       if (SMALL_INT (offset))
                   1641:        output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
                   1642:       else
                   1643:        output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
                   1644:     }
                   1645:   else
                   1646:     abort ();
                   1647: }
                   1648: 
                   1649: /* Output code to place a size count SIZE in register REG.
                   1650:    ALIGN is the size of the unit of transfer.
                   1651: 
                   1652:    Because block moves are pipelined, we don't include the
                   1653:    first element in the transfer of SIZE to REG.  */
                   1654: 
                   1655: static void
                   1656: output_size_for_block_move (size, reg, align)
                   1657:      rtx size, reg;
                   1658:      rtx align;
                   1659: {
                   1660:   rtx xoperands[3];
                   1661: 
                   1662:   xoperands[0] = reg;
                   1663:   xoperands[1] = size;
                   1664:   xoperands[2] = align;
                   1665:   if (GET_CODE (size) == REG)
                   1666:     output_asm_insn ("sub %1,%2,%0", xoperands);
                   1667:   else
                   1668:     {
                   1669:       xoperands[1]
                   1670:        = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
                   1671:       output_asm_insn ("set %1,%0", xoperands);
                   1672:     }
                   1673: }
                   1674: 
                   1675: /* Emit code to perform a block move.
                   1676: 
                   1677:    OPERANDS[0] is the destination.
                   1678:    OPERANDS[1] is the source.
                   1679:    OPERANDS[2] is the size.
                   1680:    OPERANDS[3] is the alignment safe to use.
                   1681:    OPERANDS[4] is a register we can safely clobber as a temp.  */
                   1682: 
                   1683: char *
                   1684: output_block_move (operands)
                   1685:      rtx *operands;
                   1686: {
                   1687:   /* A vector for our computed operands.  Note that load_output_address
                   1688:      makes use of (and can clobber) up to the 8th element of this vector.  */
                   1689:   rtx xoperands[10];
                   1690:   rtx zoperands[10];
                   1691:   static int movstrsi_label = 0;
                   1692:   int i;
                   1693:   rtx temp1 = operands[4];
                   1694:   rtx sizertx = operands[2];
                   1695:   rtx alignrtx = operands[3];
                   1696:   int align = INTVAL (alignrtx);
1.1.1.3 ! root     1697:   char label3[30], label5[30];
1.1       root     1698: 
                   1699:   xoperands[0] = operands[0];
                   1700:   xoperands[1] = operands[1];
                   1701:   xoperands[2] = temp1;
                   1702: 
1.1.1.2   root     1703:   /* We can't move more than this many bytes at a time because we have only
                   1704:      one register, %g1, to move them through.  */
                   1705:   if (align > UNITS_PER_WORD)
                   1706:     {
                   1707:       align = UNITS_PER_WORD;
                   1708:       alignrtx = gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD);
                   1709:     }
                   1710: 
                   1711:   /* We consider 8 ld/st pairs, for a total of 16 inline insns to be
                   1712:      reasonable here.  (Actually will emit a maximum of 18 inline insns for
                   1713:      the case of size == 31 and align == 4).  */
                   1714: 
                   1715:   if (GET_CODE (sizertx) == CONST_INT && (INTVAL (sizertx) / align) <= 8
                   1716:       && memory_address_p (QImode, plus_constant_for_output (xoperands[0],
                   1717:                                                             INTVAL (sizertx)))
                   1718:       && memory_address_p (QImode, plus_constant_for_output (xoperands[1],
                   1719:                                                             INTVAL (sizertx))))
1.1       root     1720:     {
1.1.1.2   root     1721:       int size = INTVAL (sizertx);
                   1722:       int offset = 0;
                   1723: 
                   1724:       /* We will store different integers into this particular RTX.  */
                   1725:       xoperands[2] = rtx_alloc (CONST_INT);
                   1726:       PUT_MODE (xoperands[2], VOIDmode);
                   1727: 
                   1728:       /* This case is currently not handled.  Abort instead of generating
                   1729:         bad code.  */
                   1730:       if (align > 4)
                   1731:        abort ();
                   1732: 
                   1733:       if (align >= 4)
                   1734:        {
                   1735:          for (i = (size >> 2) - 1; i >= 0; i--)
                   1736:            {
                   1737:              INTVAL (xoperands[2]) = (i << 2) + offset;
                   1738:              output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
                   1739:                               xoperands);
                   1740:            }
                   1741:          offset += (size & ~0x3);
                   1742:          size = size & 0x3;
                   1743:          if (size == 0)
                   1744:            return "";
                   1745:        }
                   1746: 
                   1747:       if (align >= 2)
                   1748:        {
                   1749:          for (i = (size >> 1) - 1; i >= 0; i--)
                   1750:            {
                   1751:              INTVAL (xoperands[2]) = (i << 1) + offset;
                   1752:              output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
                   1753:                               xoperands);
                   1754:            }
                   1755:          offset += (size & ~0x1);
                   1756:          size = size & 0x1;
                   1757:          if (size == 0)
                   1758:            return "";
                   1759:        }
                   1760: 
                   1761:       if (align >= 1)
                   1762:        {
                   1763:          for (i = size - 1; i >= 0; i--)
                   1764:            {
                   1765:              INTVAL (xoperands[2]) = i + offset;
                   1766:              output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
                   1767:                               xoperands);
                   1768:            }
                   1769:          return "";
                   1770:        }
                   1771: 
                   1772:       /* We should never reach here.  */
                   1773:       abort ();
1.1       root     1774:     }
                   1775: 
                   1776:   /* If the size isn't known to be a multiple of the alignment,
                   1777:      we have to do it in smaller pieces.  If we could determine that
                   1778:      the size was a multiple of 2 (or whatever), we could be smarter
                   1779:      about this.  */
                   1780:   if (GET_CODE (sizertx) != CONST_INT)
                   1781:     align = 1;
                   1782:   else
                   1783:     {
                   1784:       int size = INTVAL (sizertx);
                   1785:       while (size % align)
                   1786:        align >>= 1;
                   1787:     }
                   1788: 
                   1789:   if (align != INTVAL (alignrtx))
                   1790:     alignrtx = gen_rtx (CONST_INT, VOIDmode, align);
                   1791: 
                   1792:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1793:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
                   1794:   xoperands[5] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                   1795: 
1.1.1.3 ! root     1796:   ASM_GENERATE_INTERNAL_LABEL (label3, "Lm", INTVAL (xoperands[3]));
        !          1797:   ASM_GENERATE_INTERNAL_LABEL (label5, "Lm", INTVAL (xoperands[5]));
        !          1798: 
1.1.1.2   root     1799:   /* This is the size of the transfer.  Emit code to decrement the size
                   1800:      value by ALIGN, and store the result in the temp1 register.  */
1.1       root     1801:   output_size_for_block_move (sizertx, temp1, alignrtx);
                   1802: 
                   1803:   /* Must handle the case when the size is zero or negative, so the first thing
                   1804:      we do is compare the size against zero, and only copy bytes if it is
                   1805:      zero or greater.  Note that we have already subtracted off the alignment
                   1806:      once, so we must copy 1 alignment worth of bytes if the size is zero
                   1807:      here.
                   1808: 
                   1809:      The SUN assembler complains about labels in branch delay slots, so we
1.1.1.2   root     1810:      do this before outputting the load address, so that there will always
1.1       root     1811:      be a harmless insn between the branch here and the next label emitted
                   1812:      below.  */
                   1813: 
1.1.1.3 ! root     1814:   {
        !          1815:     char pattern[100];
        !          1816: 
        !          1817:     sprintf (pattern, "cmp %%2,0\n\tbl %s", &label5[1]);
        !          1818:     output_asm_insn (pattern, xoperands);
        !          1819:   }
1.1       root     1820: 
                   1821:   zoperands[0] = operands[0];
                   1822:   zoperands[3] = plus_constant_for_output (operands[0], align);
                   1823:   output_load_address (zoperands);
                   1824: 
                   1825:   /* ??? This might be much faster if the loops below were preconditioned
                   1826:      and unrolled.
                   1827: 
                   1828:      That is, at run time, copy enough bytes one at a time to ensure that the
                   1829:      target and source addresses are aligned to the the largest possible
                   1830:      alignment.  Then use a preconditioned unrolled loop to copy say 16
                   1831:      bytes at a time.  Then copy bytes one at a time until finish the rest.  */
                   1832: 
                   1833:   /* Output the first label separately, so that it is spaced properly.  */
                   1834: 
                   1835:   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "Lm", INTVAL (xoperands[3]));
                   1836: 
1.1.1.3 ! root     1837:   {
        !          1838:     char pattern[200];
        !          1839:     register char *ld_suffix = (align == 1) ? "ub" : (align == 2) ? "uh" : "";
        !          1840:     register char *st_suffix = (align == 1) ? "b" : (align == 2) ? "h" : "";
        !          1841: 
        !          1842:     sprintf (pattern, "ld%s [%%1+%%2],%%%%g1\n\tsubcc %%2,%%4,%%2\n\tbge %s\n\tst%s %%%%g1,[%%0+%%2]\n%s:", ld_suffix, &label3[1], st_suffix, &label5[1]);
        !          1843:     output_asm_insn (pattern, xoperands);
        !          1844:   }
        !          1845: 
1.1       root     1846:   return "";
                   1847: }
                   1848: 
                   1849: /* Output reasonable peephole for set-on-condition-code insns.
                   1850:    Note that these insns assume a particular way of defining
                   1851:    labels.  Therefore, *both* sparc.h and this function must
                   1852:    be changed if a new syntax is needed.    */
                   1853: 
                   1854: char *
                   1855: output_scc_insn (operands, insn)
                   1856:      rtx operands[];
                   1857:      rtx insn;
                   1858: {
                   1859:   static char string[100];
                   1860:   rtx label = 0, next = insn;
                   1861:   int need_label = 0;
                   1862: 
                   1863:   /* Try doing a jump optimization which jump.c can't do for us
                   1864:      because we did not expose that setcc works by using branches.
                   1865: 
                   1866:      If this scc insn is followed by an unconditional branch, then have
                   1867:      the jump insn emitted here jump to that location, instead of to
                   1868:      the end of the scc sequence as usual.  */
                   1869: 
                   1870:   do
                   1871:     {
                   1872:       if (GET_CODE (next) == CODE_LABEL)
                   1873:        label = next;
                   1874:       next = NEXT_INSN (next);
                   1875:       if (next == 0)
                   1876:        break;
                   1877:     }
                   1878:   while (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL);
                   1879: 
                   1880:   /* If we are in a sequence, and the following insn is a sequence also,
                   1881:      then just following the current insn's next field will take us to the
                   1882:      first insn of the next sequence, which is the wrong place.  We don't
                   1883:      want to optimize with a branch that has had its delay slot filled.
                   1884:      Avoid this by verifying that NEXT_INSN (PREV_INSN (next)) == next
                   1885:      which fails only if NEXT is such a branch.  */
                   1886: 
                   1887:   if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next)
                   1888:       && (! final_sequence || NEXT_INSN (PREV_INSN (next)) == next))
                   1889:     label = JUMP_LABEL (next);
                   1890:   /* If not optimizing, jump label fields are not set.  To be safe, always
                   1891:      check here to whether label is still zero.  */
                   1892:   if (label == 0)
                   1893:     {
                   1894:       label = gen_label_rtx ();
                   1895:       need_label = 1;
                   1896:     }
                   1897: 
                   1898:   LABEL_NUSES (label) += 1;
                   1899: 
                   1900:   operands[2] = label;
                   1901: 
                   1902:   /* If we are in a delay slot, assume it is the delay slot of an fpcc
                   1903:      insn since our type isn't allowed anywhere else.  */
                   1904: 
                   1905:   /* ??? Fpcc instructions no longer have delay slots, so this code is
                   1906:      probably obsolete.  */
                   1907: 
                   1908:   /* The fastest way to emit code for this is an annulled branch followed
                   1909:      by two move insns.  This will take two cycles if the branch is taken,
                   1910:      and three cycles if the branch is not taken.
                   1911: 
                   1912:      However, if we are in the delay slot of another branch, this won't work,
                   1913:      because we can't put a branch in the delay slot of another branch.
                   1914:      The above sequence would effectively take 3 or 4 cycles respectively
                   1915:      since a no op would have be inserted between the two branches.
                   1916:      In this case, we want to emit a move, annulled branch, and then the
                   1917:      second move.  This sequence always takes 3 cycles, and hence is faster
                   1918:      when we are in a branch delay slot.  */
                   1919: 
                   1920:   if (final_sequence)
                   1921:     {
                   1922:       strcpy (string, "mov 0,%0\n\t");
                   1923:       strcat (string, output_cbranch (operands[1], 2, 0, 1, 0));
                   1924:       strcat (string, "\n\tmov 1,%0");
                   1925:     }
                   1926:   else
                   1927:     {
                   1928:       strcpy (string, output_cbranch (operands[1], 2, 0, 1, 0));
                   1929:       strcat (string, "\n\tmov 1,%0\n\tmov 0,%0");
                   1930:     }
                   1931: 
                   1932:   if (need_label)
                   1933:     strcat (string, "\n%l2:");
                   1934: 
                   1935:   return string;
                   1936: }
                   1937: 
                   1938: /* Vectors to keep interesting information about registers where
                   1939:    it can easily be got.  */
                   1940: 
                   1941: /* Modes for condition codes.  */
1.1.1.3 ! root     1942: #define C_MODES                                                \
        !          1943:   ((1 << (int) CCmode) | (1 << (int) CC_NOOVmode)      \
        !          1944:    | (1 << (int) CCFPmode) | (1 << (int) CCFPEmode))
1.1       root     1945: 
                   1946: /* Modes for single-word (and smaller) quantities.  */
                   1947: #define S_MODES                                                \
                   1948:  (~C_MODES                                             \
                   1949:   & ~ ((1 << (int) DImode) | (1 << (int) TImode)       \
                   1950:       | (1 << (int) DFmode) | (1 << (int) TFmode)))
                   1951: 
                   1952: /* Modes for double-word (and smaller) quantities.  */
                   1953: #define D_MODES                                        \
                   1954:   (~C_MODES                                    \
                   1955:    & ~ ((1 << (int) TImode) | (1 << (int) TFmode)))
                   1956: 
                   1957: /* Modes for quad-word quantities.  */
                   1958: #define T_MODES (~C_MODES)
                   1959: 
                   1960: /* Modes for single-float quantities.  */
                   1961: #define SF_MODES ((1 << (int) SFmode))
                   1962: 
                   1963: /* Modes for double-float quantities.  */
                   1964: #define DF_MODES (SF_MODES | (1 << (int) DFmode) | (1 << (int) SCmode))
                   1965: 
                   1966: /* Modes for quad-float quantities.  */
                   1967: #define TF_MODES (DF_MODES | (1 << (int) TFmode) | (1 << (int) DCmode))
                   1968: 
                   1969: /* Value is 1 if register/mode pair is acceptable on sparc.
                   1970:    The funny mixture of D and T modes is because integer operations
                   1971:    do not specially operate on tetra quantities, so non-quad-aligned
                   1972:    registers can hold quadword quantities (except %o4 and %i4 because
                   1973:    they cross fixed registers.  */
                   1974: 
                   1975: int hard_regno_mode_ok[] = {
                   1976:   C_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
                   1977:   T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
                   1978:   T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
                   1979:   T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
                   1980: 
                   1981:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
                   1982:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
                   1983:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
                   1984:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES};
                   1985: 
                   1986: #ifdef __GNUC__
                   1987: inline
                   1988: #endif
                   1989: static int
                   1990: save_regs (file, low, high, base, offset, n_fregs)
                   1991:      FILE *file;
                   1992:      int low, high;
                   1993:      char *base;
                   1994:      int offset;
                   1995:      int n_fregs;
                   1996: {
                   1997:   int i;
                   1998: 
                   1999:   for (i = low; i < high; i += 2)
                   2000:     {
                   2001:       if (regs_ever_live[i] && ! call_used_regs[i])
                   2002:        if (regs_ever_live[i+1] && ! call_used_regs[i+1])
                   2003:          fprintf (file, "\tstd %s,[%s+%d]\n",
                   2004:                   reg_names[i], base, offset + 4 * n_fregs),
                   2005:          n_fregs += 2;
                   2006:        else
                   2007:          fprintf (file, "\tst %s,[%s+%d]\n",
                   2008:                   reg_names[i], base, offset + 4 * n_fregs),
                   2009:          n_fregs += 2;
                   2010:       else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
                   2011:        fprintf (file, "\tst %s,[%s+%d]\n",
                   2012:                 reg_names[i+1], base, offset + 4 * n_fregs),
                   2013:        n_fregs += 2;
                   2014:     }
                   2015:   return n_fregs;
                   2016: }
                   2017: 
                   2018: #ifdef __GNUC__
                   2019: inline
                   2020: #endif
                   2021: static int
                   2022: restore_regs (file, low, high, base, offset, n_fregs)
                   2023:      FILE *file;
                   2024:      int low, high;
                   2025:      char *base;
                   2026:      int offset;
                   2027: {
                   2028:   int i;
                   2029: 
                   2030:   for (i = low; i < high; i += 2)
                   2031:     {
                   2032:       if (regs_ever_live[i] && ! call_used_regs[i])
                   2033:        if (regs_ever_live[i+1] && ! call_used_regs[i+1])
                   2034:          fprintf (file, "\tldd [%s+%d], %s\n",
                   2035:                   base, offset + 4 * n_fregs, reg_names[i]),
                   2036:          n_fregs += 2;
                   2037:        else
                   2038:          fprintf (file, "\tld [%s+%d],%s\n",
                   2039:                   base, offset + 4 * n_fregs, reg_names[i]),
                   2040:          n_fregs += 2;
                   2041:       else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
                   2042:        fprintf (file, "\tld [%s+%d],%s\n",
                   2043:                 base, offset + 4 * n_fregs, reg_names[i+1]),
                   2044:        n_fregs += 2;
                   2045:     }
                   2046:   return n_fregs;
                   2047: }
                   2048: 
                   2049: /* Static variables we want to share between prologue and epilogue.  */
                   2050: 
                   2051: /* Number of live floating point registers needed to be saved.  */
                   2052: static int num_fregs;
                   2053: 
                   2054: /* Nonzero if any floating point register was ever used.  */
                   2055: static int fregs_ever_live;
                   2056: 
                   2057: int
                   2058: compute_frame_size (size, leaf_function)
                   2059:      int size;
                   2060:      int leaf_function;
                   2061: {
                   2062:   int fregs_ever_live = 0;
                   2063:   int n_fregs = 0, i;
                   2064:   int outgoing_args_size = (current_function_outgoing_args_size
                   2065:                            + REG_PARM_STACK_SPACE (current_function_decl));
                   2066: 
                   2067:   apparent_fsize = ((size) + 7 - STARTING_FRAME_OFFSET) & -8;
                   2068:   for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2)
                   2069:     fregs_ever_live |= regs_ever_live[i]|regs_ever_live[i+1];
                   2070: 
                   2071:   if (TARGET_EPILOGUE && fregs_ever_live)
                   2072:     {
                   2073:       for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2)
                   2074:        if ((regs_ever_live[i] && ! call_used_regs[i])
                   2075:            || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
                   2076:          n_fregs += 2;
                   2077:     }
                   2078: 
                   2079:   /* Set up values for use in `function_epilogue'.  */
                   2080:   num_fregs = n_fregs;
                   2081: 
                   2082:   apparent_fsize += (outgoing_args_size+7) & -8;
                   2083:   if (leaf_function && n_fregs == 0
                   2084:       && apparent_fsize == (REG_PARM_STACK_SPACE (current_function_decl)
                   2085:                            - STARTING_FRAME_OFFSET))
                   2086:     apparent_fsize = 0;
                   2087: 
                   2088:   actual_fsize = apparent_fsize + n_fregs*4;
                   2089: 
                   2090:   /* Make sure nothing can clobber our register windows.
                   2091:      If a SAVE must be done, or there is a stack-local variable,
                   2092:      the register window area must be allocated.  */
                   2093:   if (leaf_function == 0 || size > 0)
                   2094:     actual_fsize += (16 * UNITS_PER_WORD)+8;
                   2095: 
                   2096:   return actual_fsize;
                   2097: }
                   2098: 
1.1.1.3 ! root     2099: /* Output code for the function prologue.  */
        !          2100: 
1.1       root     2101: void
                   2102: output_function_prologue (file, size, leaf_function)
                   2103:      FILE *file;
                   2104:      int size;
1.1.1.3 ! root     2105:      int leaf_function;
1.1       root     2106: {
                   2107:   if (leaf_function)
                   2108:     frame_base_name = "%sp+80";
                   2109:   else
                   2110:     frame_base_name = "%fp";
                   2111: 
1.1.1.3 ! root     2112:   /* Need to use actual_fsize, since we are also allocating
        !          2113:      space for our callee (and our own register save area).  */
1.1       root     2114:   actual_fsize = compute_frame_size (size, leaf_function);
                   2115: 
                   2116:   fprintf (file, "\t!#PROLOGUE# 0\n");
1.1.1.3 ! root     2117:   if (actual_fsize == 0)
        !          2118:     /* do nothing.  */ ;
        !          2119:   else if (actual_fsize <= 4096)
1.1       root     2120:     {
                   2121:       if (! leaf_function)
                   2122:        fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize);
                   2123:       else
                   2124:        fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize);
                   2125:     }
1.1.1.3 ! root     2126:   else if (actual_fsize <= 8192)
1.1       root     2127:     {
1.1.1.3 ! root     2128:       /* For frames in the range 4097..8192, we can use just two insns.  */
        !          2129:       if (! leaf_function)
        !          2130:        {
        !          2131:          fprintf (file, "\tsave %%sp,-4096,%%sp\n");
        !          2132:          fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
        !          2133:        }
        !          2134:       else
        !          2135:        {
        !          2136:          fprintf (file, "\tadd %%sp,-4096,%%sp\n");
        !          2137:          fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
        !          2138:        }
1.1       root     2139:     }
                   2140:   else
                   2141:     {
1.1.1.3 ! root     2142:       if (! leaf_function)
        !          2143:        {
        !          2144:          fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize);
        !          2145:          if ((actual_fsize & 0x3ff) != 0)
        !          2146:            fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize);
        !          2147:          fprintf (file, "\tsave %%sp,%%g1,%%sp\n");
        !          2148:        }
        !          2149:       else
        !          2150:        {
        !          2151:          fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize);
        !          2152:          if ((actual_fsize & 0x3ff) != 0)
        !          2153:            fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize);
        !          2154:          fprintf (file, "\tadd %%sp,%%g1,%%sp\n");
        !          2155:        }
1.1       root     2156:     }
                   2157: 
                   2158:   /* If doing anything with PIC, do it now.  */
                   2159:   if (! flag_pic)
                   2160:     fprintf (file, "\t!#PROLOGUE# 1\n");
                   2161: 
                   2162:   /* Figure out where to save any special registers.  */
                   2163:   if (num_fregs)
                   2164:     {
                   2165:       int offset, n_fregs = num_fregs;
                   2166: 
                   2167:       if (! leaf_function)
                   2168:        offset = -apparent_fsize;
                   2169:       else
                   2170:        offset = 0;
                   2171: 
                   2172:       if (TARGET_EPILOGUE && ! leaf_function)
                   2173:        n_fregs = save_regs (file, 0, 16, frame_base_name, offset, 0);
                   2174:       else if (leaf_function)
                   2175:        n_fregs = save_regs (file, 0, 32, frame_base_name, offset, 0);
                   2176:       if (TARGET_EPILOGUE)
                   2177:        save_regs (file, 32, FIRST_PSEUDO_REGISTER,
                   2178:                   frame_base_name, offset, n_fregs);
                   2179:     }
                   2180: 
                   2181:   if (regs_ever_live[62])
                   2182:     fprintf (file, "\tst %s,[%s-16]\n\tst %s,[%s-12]\n",
                   2183:             reg_names[0], frame_base_name,
                   2184:             reg_names[0], frame_base_name);
                   2185: 
                   2186:   leaf_label = 0;
                   2187:   if (leaf_function && actual_fsize != 0)
                   2188:     {
                   2189:       /* warning ("leaf procedure with frame size %d", actual_fsize); */
                   2190:       if (! TARGET_EPILOGUE)
                   2191:        leaf_label = gen_label_rtx ();
                   2192:     }
                   2193: }
                   2194: 
1.1.1.3 ! root     2195: /* Output code for the function epilogue.  */
        !          2196: 
1.1       root     2197: void
1.1.1.3 ! root     2198: output_function_epilogue (file, size, leaf_function)
1.1       root     2199:      FILE *file;
                   2200:      int size;
1.1.1.3 ! root     2201:      int leaf_function;
1.1       root     2202: {
                   2203:   int n_fregs, i;
                   2204:   char *ret;
                   2205: 
                   2206:   if (leaf_label)
                   2207:     {
                   2208:       emit_label_after (leaf_label, get_last_insn ());
                   2209:       final_scan_insn (get_last_insn (), file, 0, 0, 1);
                   2210:     }
                   2211: 
                   2212:   if (num_fregs)
                   2213:     {
                   2214:       int offset, n_fregs = num_fregs;
                   2215: 
                   2216:       if (! leaf_function)
                   2217:        offset = -apparent_fsize;
                   2218:       else
                   2219:        offset = 0;
                   2220: 
                   2221:       if (TARGET_EPILOGUE && ! leaf_function)
                   2222:        n_fregs = restore_regs (file, 0, 16, frame_base_name, offset, 0);
                   2223:       else if (leaf_function)
                   2224:        n_fregs = restore_regs (file, 0, 32, frame_base_name, offset, 0);
                   2225:       if (TARGET_EPILOGUE)
                   2226:        restore_regs (file, 32, FIRST_PSEUDO_REGISTER,
                   2227:                      frame_base_name, offset, n_fregs);
                   2228:     }
                   2229: 
                   2230:   /* Work out how to skip the caller's unimp instruction if required.  */
                   2231:   if (leaf_function)
                   2232:     ret = (current_function_returns_struct ? "jmp %o7+12" : "retl");
                   2233:   else
                   2234:     ret = (current_function_returns_struct ? "jmp %i7+12" : "ret");
                   2235: 
1.1.1.3 ! root     2236:   if (TARGET_EPILOGUE || leaf_label)
1.1       root     2237:     {
1.1.1.3 ! root     2238:       int old_target_epilogue = TARGET_EPILOGUE;
        !          2239:       target_flags &= ~old_target_epilogue;
1.1       root     2240: 
1.1.1.3 ! root     2241:       if (! leaf_function)
        !          2242:        {
        !          2243:          /* If we wound up with things in our delay slot, flush them here.  */
        !          2244:          if (current_function_epilogue_delay_list)
1.1       root     2245:            {
1.1.1.3 ! root     2246:              rtx insn = emit_jump_insn_after (gen_rtx (RETURN, VOIDmode),
        !          2247:                                               get_last_insn ());
        !          2248:              PATTERN (insn) = gen_rtx (PARALLEL, VOIDmode,
        !          2249:                                        gen_rtvec (2,
        !          2250:                                                   PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
        !          2251:                                                   PATTERN (insn)));
        !          2252:              final_scan_insn (insn, file, 1, 0, 1);
1.1       root     2253:            }
                   2254:          else
1.1.1.3 ! root     2255:            fprintf (file, "\t%s\n\trestore\n", ret);
1.1       root     2256:        }
1.1.1.3 ! root     2257:       /* All of the following cases are for leaf functions.  */
        !          2258:       else if (current_function_epilogue_delay_list)
1.1       root     2259:        {
1.1.1.3 ! root     2260:          /* eligible_for_epilogue_delay_slot ensures that if this is a
        !          2261:             leaf function, then we will only have insn in the delay slot
        !          2262:             if the frame size is zero, thus no adjust for the stack is
        !          2263:             needed here.  */
        !          2264:          if (actual_fsize != 0)
        !          2265:            abort ();
        !          2266:          fprintf (file, "\t%s\n", ret);
        !          2267:          final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
        !          2268:                           file, 1, 0, 1);
        !          2269:        }
        !          2270:       else if (actual_fsize <= 4096)
        !          2271:        fprintf (file, "\t%s\n\tsub %%sp,-%d,%%sp\n", ret, actual_fsize);
        !          2272:       else if (actual_fsize <= 8192)
        !          2273:        fprintf (file, "\tsub %%sp,-4096,%%sp\n\t%s\n\tsub %%sp,-%d,%%sp\n",
        !          2274:                 ret, actual_fsize - 4096);
        !          2275:       else if ((actual_fsize & 0x3ff) == 0)
        !          2276:        fprintf (file, "\tsethi %%hi(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
        !          2277:                 actual_fsize, ret);
        !          2278:       else              
        !          2279:        fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
        !          2280:                 actual_fsize, actual_fsize, ret);
        !          2281:       target_flags |= old_target_epilogue;
1.1       root     2282:     }
                   2283: }
                   2284: 
                   2285: /* Return the string to output a conditional branch to LABEL, which is
                   2286:    the operand number of the label.  OP is the conditional expression.  The
                   2287:    mode of register 0 says what kind of comparison we made.
                   2288: 
                   2289:    REVERSED is non-zero if we should reverse the sense of the comparison.
                   2290: 
                   2291:    ANNUL is non-zero if we should generate an annulling branch.
                   2292: 
                   2293:    NOOP is non-zero if we have to follow this branch by a noop.  */
                   2294: 
                   2295: char *
                   2296: output_cbranch (op, label, reversed, annul, noop)
                   2297:      rtx op;
                   2298:      int label;
                   2299:      int reversed, annul, noop;
                   2300: {
                   2301:   static char string[20];
                   2302:   enum rtx_code code = GET_CODE (op);
                   2303:   enum machine_mode mode = GET_MODE (XEXP (op, 0));
                   2304:   static char labelno[] = " %lX";
                   2305: 
1.1.1.2   root     2306:   /* ??? FP branches can not be preceded by another floating point insn.
1.1       root     2307:      Because there is currently no concept of pre-delay slots, we can fix
                   2308:      this only by always emitting a nop before a floating point branch.  */
                   2309: 
1.1.1.3 ! root     2310:   if (mode == CCFPmode || mode == CCFPEmode)
1.1       root     2311:     strcpy (string, "nop\n\t");
                   2312: 
                   2313:   /* If not floating-point or if EQ or NE, we can just reverse the code.  */
1.1.1.3 ! root     2314:   if (reversed
        !          2315:       && ((mode != CCFPmode && mode != CCFPEmode) || code == EQ || code == NE))
1.1       root     2316:     code = reverse_condition (code), reversed = 0;
                   2317: 
                   2318:   /* Start by writing the branch condition.  */
                   2319:   switch (code)
                   2320:     {
                   2321:     case NE:
1.1.1.3 ! root     2322:       if (mode == CCFPmode || mode == CCFPEmode)
1.1       root     2323:        strcat (string, "fbne");
                   2324:       else
                   2325:        strcpy (string, "bne");
                   2326:       break;
                   2327: 
                   2328:     case EQ:
1.1.1.3 ! root     2329:       if (mode == CCFPmode || mode == CCFPEmode)
1.1       root     2330:        strcat (string, "fbe");
                   2331:       else
                   2332:        strcpy (string, "be");
                   2333:       break;
                   2334: 
                   2335:     case GE:
1.1.1.3 ! root     2336:       if (mode == CCFPmode || mode == CCFPEmode)
1.1       root     2337:        {
                   2338:          if (reversed)
                   2339:            strcat (string, "fbul");
                   2340:          else
                   2341:            strcat (string, "fbge");
                   2342:        }
                   2343:       else if (mode == CC_NOOVmode)
                   2344:        strcpy (string, "bpos");
                   2345:       else
                   2346:        strcpy (string, "bge");
                   2347:       break;
                   2348: 
                   2349:     case GT:
1.1.1.3 ! root     2350:       if (mode == CCFPmode || mode == CCFPEmode)
1.1       root     2351:        {
                   2352:          if (reversed)
                   2353:            strcat (string, "fbule");
                   2354:          else
                   2355:            strcat (string, "fbg");
                   2356:        }
                   2357:       else
                   2358:        strcpy (string, "bg");
                   2359:       break;
                   2360: 
                   2361:     case LE:
1.1.1.3 ! root     2362:       if (mode == CCFPmode || mode == CCFPEmode)
1.1       root     2363:        {
                   2364:          if (reversed)
                   2365:            strcat (string, "fbug");
                   2366:          else
                   2367:            strcat (string, "fble");
                   2368:        }
                   2369:       else
                   2370:        strcpy (string, "ble");
                   2371:       break;
                   2372: 
                   2373:     case LT:
1.1.1.3 ! root     2374:       if (mode == CCFPmode || mode == CCFPEmode)
1.1       root     2375:        {
                   2376:          if (reversed)
                   2377:            strcat (string, "fbuge");
                   2378:          else
                   2379:            strcat (string, "fbl");
                   2380:        }
                   2381:       else if (mode == CC_NOOVmode)
                   2382:        strcpy (string, "bneg");
                   2383:       else
                   2384:        strcpy (string, "bl");
                   2385:       break;
                   2386: 
                   2387:     case GEU:
                   2388:       strcpy (string, "bgeu");
                   2389:       break;
                   2390: 
                   2391:     case GTU:
                   2392:       strcpy (string, "bgu");
                   2393:       break;
                   2394: 
                   2395:     case LEU:
                   2396:       strcpy (string, "bleu");
                   2397:       break;
                   2398: 
                   2399:     case LTU:
                   2400:       strcpy (string, "blu");
                   2401:       break;
                   2402:     }
                   2403: 
                   2404:   /* Now add the annulling, the label, and a possible noop.  */
                   2405:   if (annul)
                   2406:     strcat (string, ",a");
                   2407: 
                   2408:   labelno[3] = label + '0';
                   2409:   strcat (string, labelno);
                   2410: 
                   2411:   if (noop)
                   2412:     strcat (string, "\n\tnop");
                   2413: 
                   2414:   return string;
                   2415: }
                   2416: 
1.1.1.3 ! root     2417: /* Output assembler code to return from a function.  */
        !          2418: 
1.1       root     2419: char *
                   2420: output_return (operands)
                   2421:      rtx *operands;
                   2422: {
                   2423:   if (leaf_label)
                   2424:     {
                   2425:       operands[0] = leaf_label;
                   2426:       return "b,a %l0";
                   2427:     }
                   2428:   else if (leaf_function)
                   2429:     {
1.1.1.3 ! root     2430:       /* If we didn't allocate a frame pointer for the current function,
        !          2431:         the stack pointer might have been adjusted.  Output code to
        !          2432:         restore it now.  */
        !          2433: 
1.1       root     2434:       operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize);
1.1.1.3 ! root     2435: 
        !          2436:       /* Use sub of negated value in first two cases instead of add to
        !          2437:         allow actual_fsize == 4096.  */
        !          2438: 
        !          2439:       if (actual_fsize <= 4096)
1.1       root     2440:        {
                   2441:          if (current_function_returns_struct)
1.1.1.3 ! root     2442:            return "jmp %%o7+12\n\tsub %%sp,-%0,%%sp";
1.1       root     2443:          else
1.1.1.3 ! root     2444:            return "retl\n\tsub %%sp,-%0,%%sp";
1.1       root     2445:        }
1.1.1.3 ! root     2446:       else if (actual_fsize <= 8192)
1.1       root     2447:        {
1.1.1.3 ! root     2448:          operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize - 4096);
1.1       root     2449:          if (current_function_returns_struct)
1.1.1.3 ! root     2450:            return "sub %%sp,-4096,%%sp\n\tjmp %%o7+12\n\tsub %%sp,-%0,%%sp";
        !          2451:          else
        !          2452:            return "sub %%sp,-4096,%%sp\n\tretl\n\tsub %%sp,-%0,%%sp";
        !          2453:        }
        !          2454:       else if (current_function_returns_struct)
        !          2455:        {
        !          2456:          if ((actual_fsize & 0x3ff) != 0)
1.1       root     2457:            return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
                   2458:          else
1.1.1.3 ! root     2459:            return "sethi %%hi(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
        !          2460:        }
        !          2461:       else
        !          2462:        {
        !          2463:          if ((actual_fsize & 0x3ff) != 0)
1.1       root     2464:            return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
1.1.1.3 ! root     2465:          else
        !          2466:            return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
1.1       root     2467:        }
                   2468:     }
                   2469:   else
                   2470:     {
                   2471:       if (current_function_returns_struct)
                   2472:        return "jmp %%i7+12\n\trestore";
                   2473:       else
                   2474:        return "ret\n\trestore";
                   2475:     }
                   2476: }
                   2477: 
1.1.1.3 ! root     2478: /* Output assembler code for a SImode to SFmode conversion.  */
        !          2479: 
1.1       root     2480: char *
                   2481: output_floatsisf2 (operands)
                   2482:      rtx *operands;
                   2483: {
                   2484:   if (GET_CODE (operands[1]) == MEM)
                   2485:     return "ld %1,%0\n\tfitos %0,%0";
                   2486:   else if (FP_REG_P (operands[1]))
                   2487:     return "fitos %1,%0";
                   2488:   return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitos %0,%0";
                   2489: }
                   2490: 
1.1.1.3 ! root     2491: /* Output assembler code for a SImode to DFmode conversion.  */
        !          2492: 
1.1       root     2493: char *
                   2494: output_floatsidf2 (operands)
                   2495:      rtx *operands;
                   2496: {
                   2497:   if (GET_CODE (operands[1]) == MEM)
                   2498:     return "ld %1,%0\n\tfitod %0,%0";
                   2499:   else if (FP_REG_P (operands[1]))
                   2500:     return "fitod %1,%0";
                   2501:   return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitod %0,%0";
                   2502: }
                   2503: 
1.1.1.3 ! root     2504: /* Output assembler code for a SImode to TFmode conversion.  */
1.1       root     2505: 
1.1.1.3 ! root     2506: char *
        !          2507: output_floatsitf2 (operands)
        !          2508:      rtx *operands;
        !          2509: {
        !          2510:   if (GET_CODE (operands[1]) == MEM)
        !          2511:     return "ld %1,%0\n\tfitoq %0,%0";
        !          2512:   else if (FP_REG_P (operands[1]))
        !          2513:     return "fitoq %1,%0";
        !          2514:   return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitoq %0,%0";
1.1       root     2515: }
                   2516: 
                   2517: /* Leaf functions and non-leaf functions have different needs.  */
                   2518: 
                   2519: static int
                   2520: reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER;
                   2521: 
                   2522: static int
                   2523: reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER;
                   2524: 
                   2525: static int *reg_alloc_orders[] = {
                   2526:   reg_leaf_alloc_order,
                   2527:   reg_nonleaf_alloc_order};
                   2528: 
                   2529: void
                   2530: order_regs_for_local_alloc ()
                   2531: {
                   2532:   static int last_order_nonleaf = 1;
                   2533: 
                   2534:   if (regs_ever_live[15] != last_order_nonleaf)
                   2535:     {
                   2536:       last_order_nonleaf = !last_order_nonleaf;
                   2537:       bcopy (reg_alloc_orders[last_order_nonleaf], reg_alloc_order,
                   2538:             FIRST_PSEUDO_REGISTER * sizeof (int));
                   2539:     }
                   2540: }
                   2541: 
                   2542: /* Machine dependent routines for the branch probability, arc profiling
                   2543:    code.  */
                   2544: 
                   2545: /* The label used by the arc profiling code.  */
                   2546: 
                   2547: static rtx profiler_label;
                   2548: 
                   2549: void
                   2550: init_arc_profiler ()
                   2551: {
                   2552:   /* Generate and save a copy of this so it can be shared.  */
                   2553:   profiler_label = gen_rtx (SYMBOL_REF, Pmode, "*LPBX2");
                   2554: }
                   2555: 
                   2556: void
                   2557: output_arc_profiler (arcno, insert_after)
                   2558:      int arcno;
                   2559:      rtx insert_after;
                   2560: {
                   2561:   rtx profiler_target_addr
                   2562:     = gen_rtx (CONST, Pmode,
                   2563:               gen_rtx (PLUS, Pmode, profiler_label,
                   2564:                        gen_rtx (CONST_INT, VOIDmode, 4 * arcno)));
                   2565:   register rtx profiler_reg = gen_reg_rtx (SImode);
1.1.1.2   root     2566:   register rtx address_reg = gen_reg_rtx (Pmode);
                   2567:   rtx mem_ref;
                   2568: 
                   2569:   insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, address_reg,
                   2570:                                           gen_rtx (HIGH, Pmode,
                   2571:                                                    profiler_target_addr)),
                   2572:                                  insert_after);
                   2573: 
                   2574:   mem_ref = gen_rtx (MEM, SImode, gen_rtx (LO_SUM, Pmode, address_reg,
                   2575:                                           profiler_target_addr));
                   2576:   insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg,
                   2577:                                           mem_ref),
                   2578:                                  insert_after);
                   2579: 
                   2580:   insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg,
                   2581:                                           gen_rtx (PLUS, SImode, profiler_reg,
                   2582:                                                    const1_rtx)),
                   2583:                                  insert_after);
                   2584: 
                   2585:   /* This is the same rtx as above, but it is not legal to share this rtx.  */
                   2586:   mem_ref = gen_rtx (MEM, SImode, gen_rtx (LO_SUM, Pmode, address_reg,
                   2587:                                           profiler_target_addr));
                   2588:   emit_insn_after (gen_rtx (SET, VOIDmode, mem_ref, profiler_reg),
1.1       root     2589:                   insert_after);
                   2590: }
1.1.1.3 ! root     2591: 
        !          2592: /* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
        !          2593:    This makes them candidates for using ldd and std insns. 
        !          2594: 
        !          2595:    Note reg1 and reg2 *must* be hard registers.  To be sure we will
        !          2596:    abort if we are passed pseudo registers.  */
        !          2597: 
        !          2598: int
        !          2599: registers_ok_for_ldd (reg1, reg2)
        !          2600:      rtx reg1, reg2;
1.1       root     2601: {
                   2602: 
1.1.1.3 ! root     2603:   /* We might have been passed a SUBREG.  */
        !          2604:   if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) 
        !          2605:     return 0;
        !          2606: 
        !          2607:   /* Should never happen.  */
        !          2608:   if (REGNO (reg1) > FIRST_PSEUDO_REGISTER 
        !          2609:       || REGNO (reg2) > FIRST_PSEUDO_REGISTER)
        !          2610:     abort ();
        !          2611: 
        !          2612:   if (REGNO (reg1) % 2 != 0)
        !          2613:     return 0;
        !          2614: 
        !          2615:   return (REGNO (reg1) == REGNO (reg2) - 1);
        !          2616:   
        !          2617: }
        !          2618: 
        !          2619: /* Return 1 if addr1 and addr2 are suitable for use in an ldd or 
        !          2620:    std insn.
1.1       root     2621: 
1.1.1.3 ! root     2622:    This can only happen when addr1 and addr2 are consecutive memory
        !          2623:    locations (addr1 + 4 == addr2).  addr1 must also be aligned on a 
        !          2624:    64 bit boundary (addr1 % 8 == 0).  
1.1       root     2625: 
1.1.1.3 ! root     2626:    We know %sp and %fp are kept aligned on a 64 bit boundary.  Other
        !          2627:    registers are assumed to *never* be properly aligned and are 
        !          2628:    rejected.
1.1       root     2629: 
1.1.1.3 ! root     2630:    Knowing %sp and %fp are kept aligned on a 64 bit boundary, we 
        !          2631:    need only check that the offset for addr1 % 8 == 0.  */
        !          2632: 
        !          2633: int
        !          2634: memory_ok_for_ldd (addr1, addr2)
        !          2635:       rtx addr1, addr2;
        !          2636: {
        !          2637:   int reg1, offset1;
1.1       root     2638: 
1.1.1.3 ! root     2639:   /* Extract a register number and offset (if used) from the first addr.  */
        !          2640:   if (GET_CODE (addr1) == PLUS)
1.1       root     2641:     {
1.1.1.3 ! root     2642:       /* If not a REG, return zero.  */
        !          2643:       if (GET_CODE (XEXP (addr1, 0)) != REG)
        !          2644:        return 0;
1.1       root     2645:       else
1.1.1.3 ! root     2646:        {
        !          2647:           reg1 = REGNO (XEXP (addr1, 0));
        !          2648:          /* The offset must be constant!  */
        !          2649:          if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
        !          2650:             return 0;
        !          2651:           offset1 = INTVAL (XEXP (addr1, 1));
        !          2652:        }
1.1       root     2653:     }
1.1.1.3 ! root     2654:   else if (GET_CODE (addr1) != REG)
        !          2655:     return 0;
1.1       root     2656:   else
                   2657:     {
1.1.1.3 ! root     2658:       reg1 = REGNO (addr1);
        !          2659:       /* This was a simple (mem (reg)) expression.  Offset is 0.  */
        !          2660:       offset1 = 0;
1.1       root     2661:     }
1.1.1.3 ! root     2662: 
        !          2663:   /* Make sure the second address is a (mem (plus (reg) (const_int).  */
        !          2664:   if (GET_CODE (addr2) != PLUS)
        !          2665:     return 0;
        !          2666: 
        !          2667:   if (GET_CODE (XEXP (addr2, 0)) != REG
        !          2668:       || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
        !          2669:     return 0;
        !          2670: 
        !          2671:   /* Only %fp and %sp are allowed.  Additionally both addresses must
        !          2672:      use the same register.  */
        !          2673:   if (reg1 != FRAME_POINTER_REGNUM && reg1 != STACK_POINTER_REGNUM)
        !          2674:     return 0;
        !          2675: 
        !          2676:   if (reg1 != REGNO (XEXP (addr2, 0)))
        !          2677:     return 0;
        !          2678: 
        !          2679:   /* The first offset must be evenly divisable by 8 to ensure the 
        !          2680:      address is 64 bit aligned.  */
        !          2681:   if (offset1 % 8 != 0)
        !          2682:     return 0;
        !          2683: 
        !          2684:   /* The offset for the second addr must be 4 more than the first addr.  */
        !          2685:   if (INTVAL (XEXP (addr2, 1)) != offset1 + 4)
        !          2686:     return 0;
        !          2687: 
        !          2688:   /* All the tests passed.  addr1 and addr2 are valid for ldd and std
        !          2689:      instructions.  */
        !          2690:   return 1;
1.1       root     2691: }
                   2692: 
                   2693: /* Print operand X (an rtx) in assembler syntax to file FILE.
                   2694:    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
                   2695:    For `%' followed by punctuation, CODE is the punctuation and X is null.  */
                   2696: 
                   2697: void
                   2698: print_operand (file, x, code)
                   2699:      FILE *file;
                   2700:      rtx x;
                   2701:      int code;
                   2702: {
                   2703:   switch (code)
                   2704:     {
                   2705:     case '#':
                   2706:       /* Output a 'nop' if there's nothing for the delay slot.  */
                   2707:       if (dbr_sequence_length () == 0)
                   2708:        fputs ("\n\tnop", file);
                   2709:       return;
                   2710:     case '*':
                   2711:       /* Output an annul flag if there's nothing for the delay slot.  */
                   2712:       if (dbr_sequence_length () == 0)
                   2713:         fputs (",a", file);
                   2714:       return;
                   2715:     case 'Y':
                   2716:       /* Adjust the operand to take into account a RESTORE operation.  */
                   2717:       if (GET_CODE (x) != REG)
                   2718:        abort ();
                   2719:       if (REGNO (x) < 8)
                   2720:        fputs (reg_names[REGNO (x)], file);
                   2721:       else if (REGNO (x) >= 24 && REGNO (x) < 32)
                   2722:        fputs (reg_names[REGNO (x)-16], file);
                   2723:       else
                   2724:        abort ();
                   2725:       return;
                   2726:     case '@':
                   2727:       /* Print out what we are using as the frame pointer.  This might
                   2728:         be %fp, or might be %sp+offset.  */
                   2729:       fputs (frame_base_name, file);
                   2730:       return;
                   2731:     case 'R':
1.1.1.3 ! root     2732:       /* Print out the second register name of a register pair or quad.
1.1       root     2733:         I.e., R (%o0) => %o1.  */
                   2734:       fputs (reg_names[REGNO (x)+1], file);
                   2735:       return;
1.1.1.3 ! root     2736:     case 'S':
        !          2737:       /* Print out the third register name of a register quad.
        !          2738:         I.e., S (%o0) => %o2.  */
        !          2739:       fputs (reg_names[REGNO (x)+2], file);
        !          2740:       return;
        !          2741:     case 'T':
        !          2742:       /* Print out the fourth register name of a register quad.
        !          2743:         I.e., T (%o0) => %o3.  */
        !          2744:       fputs (reg_names[REGNO (x)+3], file);
        !          2745:       return;
1.1       root     2746:     case 'm':
                   2747:       /* Print the operand's address only.  */
                   2748:       output_address (XEXP (x, 0));
                   2749:       return;
                   2750:     case 'r':
                   2751:       /* In this case we need a register.  Use %g0 if the
1.1.1.3 ! root     2752:         operand is const0_rtx.  */
        !          2753:       if (x == const0_rtx
        !          2754:          || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
1.1       root     2755:        {
                   2756:          fputs ("%g0", file);
                   2757:          return;
                   2758:        }
                   2759:       else
                   2760:        break;
                   2761: 
                   2762:     case  'A':
                   2763:       switch (GET_CODE (x))
                   2764:        {
                   2765:        case IOR: fputs ("or", file); break;
                   2766:        case AND: fputs ("and", file); break;
                   2767:        case XOR: fputs ("xor", file); break;
                   2768:        default: abort ();
                   2769:        }
                   2770:       return;
                   2771: 
                   2772:     case 'B':
                   2773:       switch (GET_CODE (x))
                   2774:        {
                   2775:        case IOR: fputs ("orn", file); break;
                   2776:        case AND: fputs ("andn", file); break;
                   2777:        case XOR: fputs ("xnor", file); break;
                   2778:        default: abort ();
                   2779:        }
                   2780:       return;
                   2781: 
                   2782:     case 'b':
                   2783:       {
                   2784:        /* Print a sign-extended character.  */
                   2785:        int i = INTVAL (x) & 0xff;
                   2786:        if (i & 0x80)
                   2787:          i |= 0xffffff00;
                   2788:        fprintf (file, "%d", i);
                   2789:        return;
                   2790:       }
                   2791: 
                   2792:     case 0:
                   2793:       /* Do nothing special.  */
                   2794:       break;
                   2795: 
                   2796:     default:
                   2797:       /* Undocumented flag.  */
                   2798:       abort ();
                   2799:     }
                   2800: 
                   2801:   if (GET_CODE (x) == REG)
                   2802:     fputs (reg_names[REGNO (x)], file);
                   2803:   else if (GET_CODE (x) == MEM)
                   2804:     {
                   2805:       fputc ('[', file);
                   2806:       if (CONSTANT_P (XEXP (x, 0)))
                   2807:        /* Poor Sun assembler doesn't understand absolute addressing.  */
                   2808:        fputs ("%g0+", file);
                   2809:       output_address (XEXP (x, 0));
                   2810:       fputc (']', file);
                   2811:     }
                   2812:   else if (GET_CODE (x) == HIGH)
                   2813:     {
                   2814:       fputs ("%hi(", file);
                   2815:       output_addr_const (file, XEXP (x, 0));
                   2816:       fputc (')', file);
                   2817:     }
                   2818:   else if (GET_CODE (x) == LO_SUM)
                   2819:     {
                   2820:       print_operand (file, XEXP (x, 0), 0);
                   2821:       fputs ("+%lo(", file);
                   2822:       output_addr_const (file, XEXP (x, 1));
                   2823:       fputc (')', file);
                   2824:     }
                   2825:   else if (GET_CODE (x) == CONST_DOUBLE)
                   2826:     {
                   2827:       if (CONST_DOUBLE_HIGH (x) == 0)
                   2828:        fprintf (file, "%u", CONST_DOUBLE_LOW (x));
                   2829:       else if (CONST_DOUBLE_HIGH (x) == -1
                   2830:               && CONST_DOUBLE_LOW (x) < 0)
                   2831:        fprintf (file, "%d", CONST_DOUBLE_LOW (x));
                   2832:       else
                   2833:        abort ();
                   2834:     }
                   2835:   else { output_addr_const (file, x); }
                   2836: }
                   2837: 
                   2838: /* This function outputs assembler code for VALUE to FILE, where VALUE is
                   2839:    a 64 bit (DImode) value.  */
                   2840: 
                   2841: /* ??? If there is a 64 bit counterpart to .word that the assembler
                   2842:    understands, then using that would simply this code greatly.  */
                   2843: 
                   2844: void
                   2845: output_double_int (file, value)
                   2846:      FILE *file;
                   2847:      rtx value;
                   2848: {
                   2849:   if (GET_CODE (value) == CONST_INT)
                   2850:     {
                   2851:       if (INTVAL (value) < 0)
                   2852:        ASM_OUTPUT_INT (file, constm1_rtx);
                   2853:       else
                   2854:        ASM_OUTPUT_INT (file, const0_rtx);
                   2855:       ASM_OUTPUT_INT (file, value);
                   2856:     }
                   2857:   else if (GET_CODE (value) == CONST_DOUBLE)
                   2858:     {
                   2859:       ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode,
                   2860:                                     CONST_DOUBLE_HIGH (value)));
                   2861:       ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode,
                   2862:                                     CONST_DOUBLE_LOW (value)));
                   2863:     }
                   2864:   else if (GET_CODE (value) == SYMBOL_REF
                   2865:           || GET_CODE (value) == CONST
                   2866:           || GET_CODE (value) == PLUS)
                   2867:     {
                   2868:       /* Addresses are only 32 bits.  */
                   2869:       ASM_OUTPUT_INT (file, const0_rtx);
                   2870:       ASM_OUTPUT_INT (file, value);
                   2871:     }
                   2872:   else
                   2873:     abort ();
                   2874: }
1.1.1.3 ! root     2875: 
        !          2876: #ifndef CHAR_TYPE_SIZE
        !          2877: #define CHAR_TYPE_SIZE BITS_PER_UNIT
        !          2878: #endif
        !          2879: 
        !          2880: #ifndef SHORT_TYPE_SIZE
        !          2881: #define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2)
        !          2882: #endif
        !          2883: 
        !          2884: #ifndef INT_TYPE_SIZE
        !          2885: #define INT_TYPE_SIZE BITS_PER_WORD
        !          2886: #endif
        !          2887: 
        !          2888: #ifndef LONG_TYPE_SIZE
        !          2889: #define LONG_TYPE_SIZE BITS_PER_WORD
        !          2890: #endif
        !          2891: 
        !          2892: #ifndef LONG_LONG_TYPE_SIZE
        !          2893: #define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
        !          2894: #endif
        !          2895: 
        !          2896: #ifndef FLOAT_TYPE_SIZE
        !          2897: #define FLOAT_TYPE_SIZE BITS_PER_WORD
        !          2898: #endif
        !          2899: 
        !          2900: #ifndef DOUBLE_TYPE_SIZE
        !          2901: #define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
        !          2902: #endif
        !          2903: 
        !          2904: #ifndef LONG_DOUBLE_TYPE_SIZE
        !          2905: #define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
        !          2906: #endif
        !          2907: 
        !          2908: unsigned long
        !          2909: sparc_type_code (type)
        !          2910:      register tree type;
        !          2911: {
        !          2912:   register unsigned long qualifiers = 0;
        !          2913:   register unsigned shift = 6;
        !          2914: 
        !          2915:   for (;;)
        !          2916:     {
        !          2917:       switch (TREE_CODE (type))
        !          2918:        {
        !          2919:        case ERROR_MARK:
        !          2920:          return qualifiers;
        !          2921:   
        !          2922:        case ARRAY_TYPE:
        !          2923:          qualifiers |= (3 << shift);
        !          2924:          shift += 2;
        !          2925:          type = TREE_TYPE (type);
        !          2926:          break;
        !          2927: 
        !          2928:        case FUNCTION_TYPE:
        !          2929:        case METHOD_TYPE:
        !          2930:          qualifiers |= (2 << shift);
        !          2931:          shift += 2;
        !          2932:          type = TREE_TYPE (type);
        !          2933:          break;
        !          2934: 
        !          2935:        case POINTER_TYPE:
        !          2936:        case REFERENCE_TYPE:
        !          2937:        case OFFSET_TYPE:
        !          2938:          qualifiers |= (1 << shift);
        !          2939:          shift += 2;
        !          2940:          type = TREE_TYPE (type);
        !          2941:          break;
        !          2942: 
        !          2943:        case RECORD_TYPE:
        !          2944:          return (qualifiers | 8);
        !          2945: 
        !          2946:        case UNION_TYPE:
        !          2947:          return (qualifiers | 9);
        !          2948: 
        !          2949:        case ENUMERAL_TYPE:
        !          2950:          return (qualifiers | 10);
1.1       root     2951: 
1.1.1.3 ! root     2952:        case VOID_TYPE:
        !          2953:          return (qualifiers | 16);
        !          2954: 
        !          2955:        case INTEGER_TYPE:
        !          2956:          /* Carefully distinguish all the standard types of C,
        !          2957:             without messing up if the language is not C.
        !          2958:             Note that we check only for the names that contain spaces;
        !          2959:             other names might occur by coincidence in other languages.  */
        !          2960:          if (TYPE_NAME (type) != 0
        !          2961:              && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
        !          2962:              && DECL_NAME (TYPE_NAME (type)) != 0
        !          2963:              && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE)
        !          2964:            {
        !          2965:              char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
        !          2966:   
        !          2967:              if (!strcmp (name, "unsigned char"))
        !          2968:                return (qualifiers | 12);
        !          2969:              if (!strcmp (name, "signed char"))
        !          2970:                return (qualifiers | 2);
        !          2971:              if (!strcmp (name, "unsigned int"))
        !          2972:                return (qualifiers | 14);
        !          2973:              if (!strcmp (name, "short int"))
        !          2974:                return (qualifiers | 3);
        !          2975:              if (!strcmp (name, "short unsigned int"))
        !          2976:                return (qualifiers | 13);
        !          2977:              if (!strcmp (name, "long int"))
        !          2978:                return (qualifiers | 5);
        !          2979:              if (!strcmp (name, "long unsigned int"))
        !          2980:                return (qualifiers | 15);
        !          2981:              if (!strcmp (name, "long long int"))
        !          2982:                return (qualifiers | 5);        /* Who knows? */
        !          2983:              if (!strcmp (name, "long long unsigned int"))
        !          2984:                return (qualifiers | 15);       /* Who knows? */
        !          2985:            }
        !          2986:   
        !          2987:          /* Most integer types will be sorted out above, however, for the
        !          2988:             sake of special `array index' integer types, the following code
        !          2989:             is also provided.  */
        !          2990:   
        !          2991:          if (TYPE_PRECISION (type) == INT_TYPE_SIZE)
        !          2992:            return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4));
        !          2993:   
        !          2994:          if (TYPE_PRECISION (type) == LONG_TYPE_SIZE)
        !          2995:            return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
        !          2996:   
        !          2997:          if (TYPE_PRECISION (type) == LONG_LONG_TYPE_SIZE)
        !          2998:            return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
        !          2999:   
        !          3000:          if (TYPE_PRECISION (type) == SHORT_TYPE_SIZE)
        !          3001:            return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3));
        !          3002:   
        !          3003:          if (TYPE_PRECISION (type) == CHAR_TYPE_SIZE)
        !          3004:            return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2));
        !          3005:   
        !          3006:          abort ();
        !          3007:   
        !          3008:        case REAL_TYPE:
        !          3009:          /* Carefully distinguish all the standard types of C,
        !          3010:             without messing up if the language is not C.  */
        !          3011:          if (TYPE_NAME (type) != 0
        !          3012:              && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
        !          3013:              && DECL_NAME (TYPE_NAME (type)) != 0
        !          3014:              && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE)
        !          3015:            {
        !          3016:              char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
        !          3017:   
        !          3018:              if (!strcmp (name, "long double"))
        !          3019:                return (qualifiers | 7);        /* Who knows? */
        !          3020:            }
        !          3021:   
        !          3022:          if (TYPE_PRECISION (type) == DOUBLE_TYPE_SIZE)
        !          3023:            return (qualifiers | 7);
        !          3024:          if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE)
        !          3025:            return (qualifiers | 6);
        !          3026:          if (TYPE_PRECISION (type) == LONG_DOUBLE_TYPE_SIZE)
        !          3027:            return (qualifiers | 7);    /* Who knows? */
        !          3028:          abort ();
        !          3029:   
        !          3030:        case COMPLEX_TYPE:      /* GNU Fortran COMPLEX type.  */
        !          3031:        case CHAR_TYPE:         /* GNU Pascal CHAR type.  Not used in C.  */
        !          3032:        case BOOLEAN_TYPE:      /* GNU Fortran BOOLEAN type.  */
        !          3033:        case FILE_TYPE:         /* GNU Pascal FILE type.  */
        !          3034:        case STRING_TYPE:       /* GNU Fortran STRING type. */
        !          3035:        case LANG_TYPE:         /* ? */
        !          3036:          abort ();
        !          3037:   
        !          3038:        default:
        !          3039:          abort ();             /* Not a type! */
        !          3040:         }
        !          3041:     }
        !          3042: }
        !          3043: 
        !          3044: #ifdef HANDLE_PRAGMA
        !          3045: 
        !          3046: /* Handle a pragma directive.  HANDLE_PRAGMA conspires to parse the
        !          3047:    input following #pragma into tokens based on yylex.  TOKEN is the
        !          3048:    current token, and STRING is its printable form.  */
        !          3049: 
        !          3050: void
        !          3051: handle_pragma_token (string, token)
        !          3052:      char *string;
        !          3053:      tree token;
        !          3054: {
        !          3055:   static enum pragma_state
        !          3056:     {
        !          3057:       ps_start,
        !          3058:       ps_done,
        !          3059:       ps_bad,
        !          3060:       ps_weak,
        !          3061:       ps_name,
        !          3062:       ps_equals,
        !          3063:       ps_value,
        !          3064:       } state = ps_start, type;
        !          3065:   static char *name;
        !          3066:   static char *value;
        !          3067:   static int align;
        !          3068: 
        !          3069:   if (string == 0)
        !          3070:     {
        !          3071: #ifdef WEAK_ASM_OP
        !          3072:       if (type == ps_weak)
        !          3073:        {
        !          3074:          if (state == ps_name || state == ps_value)
        !          3075:            {
        !          3076:              fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
        !          3077:              ASM_OUTPUT_LABELREF (asm_out_file, name);
        !          3078:              fputc ('\n', asm_out_file);
        !          3079:              if (state == ps_value)
        !          3080:                {
        !          3081:                  fputc ('\t', asm_out_file);
        !          3082:                  ASM_OUTPUT_LABELREF (asm_out_file, name);
        !          3083:                  fputs (" = ", asm_out_file);
        !          3084:                  ASM_OUTPUT_LABELREF (asm_out_file, value);
        !          3085:                  fputc ('\n', asm_out_file);
        !          3086:                }
        !          3087:            }
        !          3088:          else if (! (state == ps_done || state == ps_start))
        !          3089:            warning ("ignoring malformed #pragma weak symbol [=value]");
        !          3090:        }
        !          3091: #endif /* WEAK_ASM_OP */
        !          3092: 
        !          3093:       type = state = ps_start;
        !          3094:       return;
        !          3095:     }
        !          3096: 
        !          3097:   switch (state)
        !          3098:     {
        !          3099:     case ps_start:
        !          3100:       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
        !          3101:        {
        !          3102: #ifdef WEAK_ASM_OP
        !          3103:          if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
        !          3104:            type = state = ps_weak;
        !          3105:          else
        !          3106: #endif
        !          3107:            type = state = ps_done;
        !          3108:        }
        !          3109:       else
        !          3110:        type = state = ps_done;
        !          3111:       break;
        !          3112: 
        !          3113: #ifdef WEAK_ASM_OP
        !          3114:     case ps_weak:
        !          3115:       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
        !          3116:        {
        !          3117:          name = IDENTIFIER_POINTER (token);
        !          3118:          state = ps_name;
        !          3119:        }
        !          3120:       else
        !          3121:        state = ps_bad;
        !          3122:       break;
        !          3123: 
        !          3124:     case ps_name:
        !          3125:       state = (strcmp (string, "=") ? ps_bad : ps_equals);
        !          3126:       break;
        !          3127: 
        !          3128:     case ps_equals:
        !          3129:       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
        !          3130:        {
        !          3131:          value = IDENTIFIER_POINTER (token);
        !          3132:          state = ps_value;
        !          3133:        }
        !          3134:       else
        !          3135:        state = ps_bad;
        !          3136:       break;
        !          3137: 
        !          3138:     case ps_value:
        !          3139:       state = ps_bad;
        !          3140:       break;
        !          3141: #endif /* WEAK_ASM_OP */
        !          3142: 
        !          3143:     case ps_bad:
        !          3144:     case ps_done:
        !          3145:       break;
        !          3146: 
        !          3147:     default:
        !          3148:       abort ();
        !          3149:     }
        !          3150: }
        !          3151: #endif /* HANDLE_PRAGMA */

unix.superglobalmegacorp.com

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