Annotation of GNUtools/cc/config/sparc/sparc.c, revision 1.1

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

unix.superglobalmegacorp.com

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