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

1.1     ! root        1: /* Subroutines for insn-output.c for Sun SPARC.
        !             2:    Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
        !             3:    Contributed by Michael Tiemann ([email protected])
        !             4: 
        !             5: This file is part of GNU CC.
        !             6: 
        !             7: GNU CC is free software; you can redistribute it and/or modify
        !             8: it under the terms of the GNU General Public License as published by
        !             9: the Free Software Foundation; either version 2, or (at your option)
        !            10: any later version.
        !            11: 
        !            12: GNU CC is distributed in the hope that it will be useful,
        !            13: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            15: GNU General Public License for more details.
        !            16: 
        !            17: You should have received a copy of the GNU General Public License
        !            18: along with GNU CC; see the file COPYING.  If not, write to
        !            19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            20: 
        !            21: #include <stdio.h>
        !            22: #include "config.h"
        !            23: #include "rtl.h"
        !            24: #include "regs.h"
        !            25: #include "hard-reg-set.h"
        !            26: #include "real.h"
        !            27: #include "insn-config.h"
        !            28: #include "conditions.h"
        !            29: #include "insn-flags.h"
        !            30: #include "output.h"
        !            31: #include "insn-attr.h"
        !            32: #include "flags.h"
        !            33: #include "expr.h"
        !            34: #include "recog.h"
        !            35: 
        !            36: /* Global variables for machine-dependent things.  */
        !            37: 
        !            38: /* Save the operands last given to a compare for use when we
        !            39:    generate a scc or bcc insn.  */
        !            40: 
        !            41: rtx sparc_compare_op0, sparc_compare_op1;
        !            42: 
        !            43: /* We may need an epilogue if we spill too many registers.
        !            44:    If this is non-zero, then we branch here for the epilogue.  */
        !            45: static rtx leaf_label;
        !            46: 
        !            47: #ifdef LEAF_REGISTERS
        !            48: 
        !            49: /* Vector to say how input registers are mapped to output
        !            50:    registers.  FRAME_POINTER_REGNUM cannot be remapped by
        !            51:    this function to eliminate it.  You must use -fomit-frame-pointer
        !            52:    to get that.  */
        !            53: char leaf_reg_remap[] =
        !            54: { 0, 1, 2, 3, 4, 5, 6, 7,
        !            55:   -1, -1, -1, -1, -1, -1, 14, -1,
        !            56:   -1, -1, -1, -1, -1, -1, -1, -1,
        !            57:   8, 9, 10, 11, 12, 13, -1, 15,
        !            58: 
        !            59:   32, 33, 34, 35, 36, 37, 38, 39,
        !            60:   40, 41, 42, 43, 44, 45, 46, 47,
        !            61:   48, 49, 50, 51, 52, 53, 54, 55,
        !            62:   56, 57, 58, 59, 60, 61, 62, 63};
        !            63: 
        !            64: char leaf_reg_backmap[] =
        !            65: { 0, 1, 2, 3, 4, 5, 6, 7,
        !            66:   24, 25, 26, 27, 28, 29, 14, 31,
        !            67:   -1, -1, -1, -1, -1, -1, -1, -1,
        !            68:   -1, -1, -1, -1, -1, -1, -1, -1,
        !            69: 
        !            70:   32, 33, 34, 35, 36, 37, 38, 39,
        !            71:   40, 41, 42, 43, 44, 45, 46, 47,
        !            72:   48, 49, 50, 51, 52, 53, 54, 55,
        !            73:   56, 57, 58, 59, 60, 61, 62, 63};
        !            74: #endif
        !            75: 
        !            76: /* Global variables set by FUNCTION_PROLOGUE.  */
        !            77: /* Size of frame.  Need to know this to emit return insns from
        !            78:    leaf procedures.  */
        !            79: int apparent_fsize;
        !            80: int actual_fsize;
        !            81: 
        !            82: /* Name of where we pretend to think the frame pointer points.
        !            83:    Normally, this is "%fp", but if we are in a leaf procedure,
        !            84:    this is "%sp+something".  */
        !            85: char *frame_base_name;
        !            86: 
        !            87: static rtx find_addr_reg ();
        !            88: 
        !            89: /* Return non-zero only if OP is a register of mode MODE,
        !            90:    or const0_rtx.  */
        !            91: int
        !            92: reg_or_0_operand (op, mode)
        !            93:      rtx op;
        !            94:      enum machine_mode mode;
        !            95: {
        !            96:   if (op == const0_rtx || register_operand (op, mode))
        !            97:     return 1;
        !            98:   if (GET_CODE (op) == CONST_DOUBLE
        !            99:       && CONST_DOUBLE_HIGH (op) == 0
        !           100:       && CONST_DOUBLE_LOW (op) == 0)
        !           101:     return 1;
        !           102:   return 0;
        !           103: }
        !           104: 
        !           105: /* Nonzero if OP can appear as the dest of a RESTORE insn.  */
        !           106: int
        !           107: restore_operand (op, mode)
        !           108:      rtx op;
        !           109:      enum machine_mode mode;
        !           110: {
        !           111:   return (GET_CODE (op) == REG && GET_MODE (op) == mode
        !           112:          && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
        !           113: }
        !           114: 
        !           115: /* PC-relative call insn on SPARC is independent of `memory_operand'.  */
        !           116: 
        !           117: int
        !           118: call_operand (op, mode)
        !           119:      rtx op;
        !           120:      enum machine_mode mode;
        !           121: {
        !           122:   if (GET_CODE (op) != MEM)
        !           123:     abort ();
        !           124:   op = XEXP (op, 0);
        !           125:   return (REG_P (op) || CONSTANT_P (op));
        !           126: }
        !           127: 
        !           128: int
        !           129: call_operand_address (op, mode)
        !           130:      rtx op;
        !           131:      enum machine_mode mode;
        !           132: {
        !           133:   return (REG_P (op) || CONSTANT_P (op));
        !           134: }
        !           135: 
        !           136: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
        !           137:    reference and a constant.  */
        !           138: 
        !           139: int
        !           140: symbolic_operand (op, mode)
        !           141:      register rtx op;
        !           142:      enum machine_mode mode;
        !           143: {
        !           144:   switch (GET_CODE (op))
        !           145:     {
        !           146:     case SYMBOL_REF:
        !           147:     case LABEL_REF:
        !           148:       return 1;
        !           149: 
        !           150:     case CONST:
        !           151:       op = XEXP (op, 0);
        !           152:       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
        !           153:               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
        !           154:              && GET_CODE (XEXP (op, 1)) == CONST_INT);
        !           155: 
        !           156:       /* This clause seems to be irrelevant.  */
        !           157:     case CONST_DOUBLE:
        !           158:       return GET_MODE (op) == mode;
        !           159: 
        !           160:     default:
        !           161:       return 0;
        !           162:     }
        !           163: }
        !           164: 
        !           165: /* Return truth value of statement that OP is a symbolic memory
        !           166:    operand of mode MODE.  */
        !           167: 
        !           168: int
        !           169: symbolic_memory_operand (op, mode)
        !           170:      rtx op;
        !           171:      enum machine_mode mode;
        !           172: {
        !           173:   if (GET_CODE (op) == SUBREG)
        !           174:     op = SUBREG_REG (op);
        !           175:   if (GET_CODE (op) != MEM)
        !           176:     return 0;
        !           177:   op = XEXP (op, 0);
        !           178:   return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
        !           179:          || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
        !           180: }
        !           181: 
        !           182: /* Return 1 if the operand is either a register or a memory operand that is
        !           183:    not symbolic.  */
        !           184: 
        !           185: int
        !           186: reg_or_nonsymb_mem_operand (op, mode)
        !           187:     register rtx op;
        !           188:     enum machine_mode mode;
        !           189: {
        !           190:   if (register_operand (op, mode))
        !           191:     return 1;
        !           192: 
        !           193:   if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
        !           194:     return 1;
        !           195: 
        !           196:   return 0;
        !           197: }
        !           198: 
        !           199: int
        !           200: sparc_operand (op, mode)
        !           201:      rtx op;
        !           202:      enum machine_mode mode;
        !           203: {
        !           204:   if (register_operand (op, mode))
        !           205:     return 1;
        !           206:   if (GET_CODE (op) == CONST_INT)
        !           207:     return SMALL_INT (op);
        !           208:   if (GET_MODE (op) != mode)
        !           209:     return 0;
        !           210:   if (GET_CODE (op) == SUBREG)
        !           211:     op = SUBREG_REG (op);
        !           212:   if (GET_CODE (op) != MEM)
        !           213:     return 0;
        !           214: 
        !           215:   op = XEXP (op, 0);
        !           216:   if (GET_CODE (op) == LO_SUM)
        !           217:     return (GET_CODE (XEXP (op, 0)) == REG
        !           218:            && symbolic_operand (XEXP (op, 1), Pmode));
        !           219:   return memory_address_p (mode, op);
        !           220: }
        !           221: 
        !           222: int
        !           223: move_operand (op, mode)
        !           224:      rtx op;
        !           225:      enum machine_mode mode;
        !           226: {
        !           227:   if (mode == DImode && arith_double_operand (op, mode))
        !           228:     return 1;
        !           229:   if (register_operand (op, mode))
        !           230:     return 1;
        !           231:   if (GET_CODE (op) == CONST_INT)
        !           232:     return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0);
        !           233: 
        !           234:   if (GET_MODE (op) != mode)
        !           235:     return 0;
        !           236:   if (GET_CODE (op) == SUBREG)
        !           237:     op = SUBREG_REG (op);
        !           238:   if (GET_CODE (op) != MEM)
        !           239:     return 0;
        !           240:   op = XEXP (op, 0);
        !           241:   if (GET_CODE (op) == LO_SUM)
        !           242:     return (register_operand (XEXP (op, 0), Pmode)
        !           243:            && CONSTANT_P (XEXP (op, 1)));
        !           244:   return memory_address_p (mode, op);
        !           245: }
        !           246: 
        !           247: int
        !           248: move_pic_label (op, mode)
        !           249:      rtx op;
        !           250:      enum machine_mode mode;
        !           251: {
        !           252:   /* Special case for PIC.  */
        !           253:   if (flag_pic && GET_CODE (op) == LABEL_REF)
        !           254:     return 1;
        !           255:   return 0;
        !           256: }
        !           257: 
        !           258: /* The rtx for the global offset table which is a special form
        !           259:    that *is* a position independent symbolic constant.  */
        !           260: rtx pic_pc_rtx;
        !           261: 
        !           262: /* Ensure that we are not using patterns that are not OK with PIC.  */
        !           263: 
        !           264: int
        !           265: check_pic (i)
        !           266:      int i;
        !           267: {
        !           268:   switch (flag_pic)
        !           269:     {
        !           270:     case 1:
        !           271:       if (GET_CODE (recog_operand[i]) == SYMBOL_REF
        !           272:          || (GET_CODE (recog_operand[i]) == CONST
        !           273:              && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
        !           274:        abort ();
        !           275:     case 2:
        !           276:     default:
        !           277:       return 1;
        !           278:     }
        !           279: }
        !           280: 
        !           281: /* Return true if X is an address which needs a temporary register when 
        !           282:    reloaded while generating PIC code.  */
        !           283: 
        !           284: int
        !           285: pic_address_needs_scratch (x)
        !           286:      rtx x;
        !           287: {
        !           288:   /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
        !           289:   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
        !           290:       && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
        !           291:       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
        !           292:       && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
        !           293:     return 1;
        !           294: 
        !           295:   return 0;
        !           296: }
        !           297: 
        !           298: int
        !           299: memop (op, mode)
        !           300:      rtx op;
        !           301:      enum machine_mode mode;
        !           302: {
        !           303:   if (GET_CODE (op) == MEM)
        !           304:     return (mode == VOIDmode || mode == GET_MODE (op));
        !           305:   return 0;
        !           306: }
        !           307: 
        !           308: /* Return truth value of whether OP is EQ or NE.  */
        !           309: 
        !           310: int
        !           311: eq_or_neq (op, mode)
        !           312:      rtx op;
        !           313:      enum machine_mode mode;
        !           314: {
        !           315:   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
        !           316: }
        !           317: 
        !           318: /* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
        !           319:    or LTU for non-floating-point.  We handle those specially.  */
        !           320: 
        !           321: int
        !           322: normal_comp_operator (op, mode)
        !           323:      rtx op;
        !           324:      enum machine_mode mode;
        !           325: {
        !           326:   enum rtx_code code = GET_CODE (op);
        !           327: 
        !           328:   if (GET_RTX_CLASS (code) != '<')
        !           329:     return 0;
        !           330: 
        !           331:   if (GET_MODE (XEXP (op, 0)) == CCFPmode)
        !           332:     return 1;
        !           333: 
        !           334:   return (code != NE && code != EQ && code != GEU && code != LTU);
        !           335: }
        !           336: 
        !           337: /* Return 1 if this is a comparison operator.  This allows the use of
        !           338:    MATCH_OPERATOR to recognize all the branch insns.  */
        !           339: 
        !           340: int
        !           341: noov_compare_op (op, mode)
        !           342:     register rtx op;
        !           343:     enum machine_mode mode;
        !           344: {
        !           345:   enum rtx_code code = GET_CODE (op);
        !           346: 
        !           347:   if (GET_RTX_CLASS (code) != '<')
        !           348:     return 0;
        !           349: 
        !           350:   if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode)
        !           351:     /* These are the only branches which work with CC_NOOVmode.  */
        !           352:     return (code == EQ || code == NE || code == GE || code == LT);
        !           353:   return 1;
        !           354: }
        !           355: 
        !           356: /* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation.  */
        !           357: 
        !           358: int
        !           359: extend_op (op, mode)
        !           360:      rtx op;
        !           361:      enum machine_mode mode;
        !           362: {
        !           363:   return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
        !           364: }
        !           365: 
        !           366: /* Return nonzero if OP is an operator of mode MODE which can set
        !           367:    the condition codes explicitly.  We do not include PLUS and MINUS
        !           368:    because these require CC_NOOVmode, which we handle explicitly.  */
        !           369: 
        !           370: int
        !           371: cc_arithop (op, mode)
        !           372:      rtx op;
        !           373:      enum machine_mode mode;
        !           374: {
        !           375:   if (GET_CODE (op) == AND
        !           376:       || GET_CODE (op) == IOR
        !           377:       || GET_CODE (op) == XOR)
        !           378:     return 1;
        !           379: 
        !           380:   return 0;
        !           381: }
        !           382: 
        !           383: /* Return nonzero if OP is an operator of mode MODE which can bitwise
        !           384:    complement its second operand and set the condition codes explicitly.  */
        !           385: 
        !           386: int
        !           387: cc_arithopn (op, mode)
        !           388:      rtx op;
        !           389:      enum machine_mode mode;
        !           390: {
        !           391:   /* XOR is not here because combine canonicalizes (xor (not ...) ...)
        !           392:      and (xor ... (not ...)) to (not (xor ...)).   */
        !           393:   return (GET_CODE (op) == AND
        !           394:          || GET_CODE (op) == IOR);
        !           395: }
        !           396: 
        !           397: /* Return truth value of whether OP can be used as an operands in a three
        !           398:    address arithmetic insn (such as add %o1,7,%l2) of mode MODE.  */
        !           399: 
        !           400: int
        !           401: arith_operand (op, mode)
        !           402:      rtx op;
        !           403:      enum machine_mode mode;
        !           404: {
        !           405:   return (register_operand (op, mode)
        !           406:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
        !           407: }
        !           408: 
        !           409: /* Return truth value of whether OP can be used as an operand in a two
        !           410:    address arithmetic insn (such as set 123456,%o4) of mode MODE.  */
        !           411: 
        !           412: int
        !           413: arith32_operand (op, mode)
        !           414:      rtx op;
        !           415:      enum machine_mode mode;
        !           416: {
        !           417:   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
        !           418: }
        !           419: 
        !           420: /* Return truth value of whether OP is a register or a CONST_DOUBLE.  */
        !           421: 
        !           422: int
        !           423: arith_double_operand (op, mode)
        !           424:      rtx op;
        !           425:      enum machine_mode mode;
        !           426: {
        !           427:   return (register_operand (op, mode)
        !           428:          || (GET_CODE (op) == CONST_DOUBLE
        !           429:              && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
        !           430:              && (unsigned) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
        !           431:              && ((CONST_DOUBLE_HIGH (op) == -1
        !           432:                   && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
        !           433:                  || (CONST_DOUBLE_HIGH (op) == 0
        !           434:                      && (CONST_DOUBLE_LOW (op) & 0x1000) == 0)))
        !           435:          || (GET_CODE (op) == CONST_INT
        !           436:              && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
        !           437:              && (unsigned) (INTVAL (op) + 0x1000) < 0x2000));
        !           438: }
        !           439: 
        !           440: /* Return truth value of whether OP is a integer which fits the
        !           441:    range constraining immediate operands in three-address insns.  */
        !           442: 
        !           443: int
        !           444: small_int (op, mode)
        !           445:      rtx op;
        !           446:      enum machine_mode mode;
        !           447: {
        !           448:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
        !           449: }
        !           450: 
        !           451: /* Return truth value of statement that OP is a call-clobbered register.  */
        !           452: int
        !           453: clobbered_register (op, mode)
        !           454:      rtx op;
        !           455:      enum machine_mode mode;
        !           456: {
        !           457:   return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
        !           458: }
        !           459: 
        !           460: /* X and Y are two things to compare using CODE.  Emit the compare insn and
        !           461:    return the rtx for register 0 in the proper mode.  */
        !           462: 
        !           463: rtx
        !           464: gen_compare_reg (code, x, y)
        !           465:      enum rtx_code code;
        !           466:      rtx x, y;
        !           467: {
        !           468:   enum machine_mode mode = SELECT_CC_MODE (code, x);
        !           469:   rtx cc_reg = gen_rtx (REG, mode, 0);
        !           470: 
        !           471:   emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
        !           472:                      gen_rtx (COMPARE, mode, x, y)));
        !           473: 
        !           474:   return cc_reg;
        !           475: }
        !           476: 
        !           477: /* Return nonzero if a return peephole merging return with
        !           478:    setting of output register is ok.  */
        !           479: int
        !           480: leaf_return_peephole_ok ()
        !           481: {
        !           482:   return (actual_fsize == 0);
        !           483: }
        !           484: 
        !           485: /* Return nonzero if TRIAL can go into the function epilogue's
        !           486:    delay slot.  SLOT is the slot we are trying to fill.  */
        !           487: 
        !           488: int
        !           489: eligible_for_epilogue_delay (trial, slot)
        !           490:      rtx trial;
        !           491:      int slot;
        !           492: {
        !           493:   static char *this_function_name;
        !           494:   rtx pat, src;
        !           495: 
        !           496:   if (slot >= 1)
        !           497:     return 0;
        !           498:   if (GET_CODE (trial) != INSN
        !           499:       || GET_CODE (PATTERN (trial)) != SET)
        !           500:     return 0;
        !           501:   if (get_attr_length (trial) != 1)
        !           502:     return 0;
        !           503: 
        !           504:   /* In the case of a true leaf function, anything can
        !           505:      go into the delay slot.  */
        !           506:   if (leaf_function)
        !           507:     {
        !           508:       if (leaf_return_peephole_ok ())
        !           509:        return (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_TRUE);
        !           510:       return 0;
        !           511:     }
        !           512: 
        !           513:   /* Otherwise, only operations which can be done in tandem with
        !           514:      a `restore' insn can go into the delay slot.  */
        !           515:   pat = PATTERN (trial);
        !           516:   if (GET_CODE (SET_DEST (pat)) != REG
        !           517:       || REGNO (SET_DEST (pat)) == 0
        !           518:       || (leaf_function
        !           519:          && REGNO (SET_DEST (pat)) < 32
        !           520:          && REGNO (SET_DEST (pat)) >= 16)
        !           521:       || (! leaf_function
        !           522:          && (REGNO (SET_DEST (pat)) >= 32
        !           523:              || REGNO (SET_DEST (pat)) < 24)))
        !           524:     return 0;
        !           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: /* Legitimize PIC addresses.  If the address is already position-independent,
        !           604:    we return ORIG.  Newly generated position-independent addresses go into a
        !           605:    reg.  This is REG if non zero, otherwise we allocate register(s) as
        !           606:    necessary.  If this is called during reload, and we need a second temp
        !           607:    register, then we use SCRATCH, which is provided via the
        !           608:    SECONDARY_INPUT_RELOAD_CLASS mechanism.  */
        !           609: 
        !           610: rtx
        !           611: legitimize_pic_address (orig, mode, reg, scratch)
        !           612:      rtx orig;
        !           613:      enum machine_mode mode;
        !           614:      rtx reg, scratch;
        !           615: {
        !           616:   if (GET_CODE (orig) == SYMBOL_REF)
        !           617:     {
        !           618:       rtx pic_ref, address;
        !           619:       rtx insn;
        !           620: 
        !           621:       if (reg == 0)
        !           622:        {
        !           623:          if (reload_in_progress)
        !           624:            abort ();
        !           625:          else
        !           626:            reg = gen_reg_rtx (Pmode);
        !           627:        }
        !           628: 
        !           629:       if (flag_pic == 2)
        !           630:        {
        !           631:          /* If not during reload, allocate another temp reg here for loading
        !           632:             in the address, so that these instructions can be optimized
        !           633:             properly.  */
        !           634:          rtx temp_reg = (reload_in_progress ? reg : gen_reg_rtx (Pmode));
        !           635: 
        !           636:          emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
        !           637:                              gen_rtx (HIGH, Pmode, orig)));
        !           638:          emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
        !           639:                              gen_rtx (LO_SUM, Pmode, temp_reg, orig)));
        !           640:          address = temp_reg;
        !           641:        }
        !           642:       else
        !           643:        address = orig;
        !           644: 
        !           645:       pic_ref = gen_rtx (MEM, Pmode,
        !           646:                         gen_rtx (PLUS, Pmode,
        !           647:                                  pic_offset_table_rtx, address));
        !           648:       current_function_uses_pic_offset_table = 1;
        !           649:       RTX_UNCHANGING_P (pic_ref) = 1;
        !           650:       insn = emit_move_insn (reg, pic_ref);
        !           651:       /* Put a REG_EQUAL note on this insn, so that it can be optimized
        !           652:         by loop.  */
        !           653:       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig,
        !           654:                                  REG_NOTES (insn));
        !           655:       return reg;
        !           656:     }
        !           657:   else if (GET_CODE (orig) == CONST)
        !           658:     {
        !           659:       rtx base, offset;
        !           660: 
        !           661:       if (GET_CODE (XEXP (orig, 0)) == PLUS
        !           662:          && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
        !           663:        return orig;
        !           664: 
        !           665:       if (reg == 0)
        !           666:        {
        !           667:          if (reload_in_progress)
        !           668:            abort ();
        !           669:          else
        !           670:            reg = gen_reg_rtx (Pmode);
        !           671:        }
        !           672: 
        !           673:       if (GET_CODE (XEXP (orig, 0)) == PLUS)
        !           674:        {
        !           675:          base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode,
        !           676:                                         reg, 0);
        !           677:          offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
        !           678:                                         base == reg ? 0 : reg, 0);
        !           679:        }
        !           680:       else
        !           681:        abort ();
        !           682: 
        !           683:       if (GET_CODE (offset) == CONST_INT)
        !           684:        {
        !           685:          if (SMALL_INT (offset))
        !           686:            return plus_constant_for_output (base, INTVAL (offset));
        !           687:          else if (! reload_in_progress)
        !           688:            offset = force_reg (Pmode, offset);
        !           689:          /* We can't create any new registers during reload, so use the
        !           690:             SCRATCH reg provided by the reload_insi pattern.  */
        !           691:          else if (scratch)
        !           692:            {
        !           693:              emit_move_insn (scratch, offset);
        !           694:              offset = scratch;
        !           695:            }
        !           696:          else
        !           697:            /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS
        !           698:               macro needs to be adjusted so that a scratch reg is provided
        !           699:               for this address.  */
        !           700:            abort ();
        !           701:        }
        !           702:       return gen_rtx (PLUS, Pmode, base, offset);
        !           703:     }
        !           704:   else if (GET_CODE (orig) == LABEL_REF)
        !           705:     current_function_uses_pic_offset_table = 1;
        !           706: 
        !           707:   return orig;
        !           708: }
        !           709: 
        !           710: /* Set up PIC-specific rtl.  This should not cause any insns
        !           711:    to be emitted.  */
        !           712: 
        !           713: void
        !           714: initialize_pic ()
        !           715: {
        !           716: }
        !           717: 
        !           718: /* Emit special PIC prologues and epilogues.  */
        !           719: 
        !           720: void
        !           721: finalize_pic ()
        !           722: {
        !           723:   /* The table we use to reference PIC data.  */
        !           724:   rtx global_offset_table;
        !           725:   /* Labels to get the PC in the prologue of this function.  */
        !           726:   rtx l1, l2;
        !           727:   rtx seq;
        !           728:   int orig_flag_pic = flag_pic;
        !           729: 
        !           730:   if (current_function_uses_pic_offset_table == 0)
        !           731:     return;
        !           732: 
        !           733:   if (! flag_pic)
        !           734:     abort ();
        !           735: 
        !           736:   flag_pic = 0;
        !           737:   l1 = gen_label_rtx ();
        !           738:   l2 = gen_label_rtx ();
        !           739: 
        !           740:   start_sequence ();
        !           741: 
        !           742:   emit_label (l1);
        !           743:   /* Note that we pun calls and jumps here!  */
        !           744:   emit_jump_insn (gen_rtx (PARALLEL, VOIDmode,
        !           745:                          gen_rtvec (2,
        !           746:                                     gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)),
        !           747:                                     gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2)))));
        !           748:   emit_label (l2);
        !           749: 
        !           750:   /* Initialize every time through, since we can't easily
        !           751:      know this to be permanent.  */
        !           752:   global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "*__GLOBAL_OFFSET_TABLE_");
        !           753:   pic_pc_rtx = gen_rtx (CONST, Pmode,
        !           754:                        gen_rtx (MINUS, Pmode,
        !           755:                                 global_offset_table,
        !           756:                                 gen_rtx (CONST, Pmode,
        !           757:                                          gen_rtx (MINUS, Pmode,
        !           758:                                                   gen_rtx (LABEL_REF, VOIDmode, l1),
        !           759:                                                   pc_rtx))));
        !           760: 
        !           761:   emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
        !           762:                      gen_rtx (HIGH, Pmode, pic_pc_rtx)));
        !           763:   emit_insn (gen_rtx (SET, VOIDmode,
        !           764:                      pic_offset_table_rtx,
        !           765:                      gen_rtx (LO_SUM, Pmode,
        !           766:                               pic_offset_table_rtx, pic_pc_rtx)));
        !           767:   emit_insn (gen_rtx (SET, VOIDmode,
        !           768:                      pic_offset_table_rtx,
        !           769:                      gen_rtx (PLUS, Pmode,
        !           770:                               pic_offset_table_rtx, gen_rtx (REG, Pmode, 15))));
        !           771:   /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */
        !           772:   LABEL_PRESERVE_P (l1) = 1;
        !           773:   LABEL_PRESERVE_P (l2) = 1;
        !           774:   flag_pic = orig_flag_pic;
        !           775: 
        !           776:   seq = gen_sequence ();
        !           777:   end_sequence ();
        !           778:   emit_insn_after (seq, get_insns ());
        !           779: 
        !           780:   /* Need to emit this whether or not we obey regdecls,
        !           781:      since setjmp/longjmp can cause life info to screw up.  */
        !           782:   emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
        !           783: }
        !           784: 
        !           785: /* For the SPARC, REG and REG+CONST is cost 0, REG+REG is cost 1,
        !           786:    and addresses involving symbolic constants are cost 2.
        !           787: 
        !           788:    We make REG+REG slightly more expensive because it might keep
        !           789:    a register live for longer than we might like.
        !           790: 
        !           791:    PIC addresses are very expensive.
        !           792: 
        !           793:    It is no coincidence that this has the same structure
        !           794:    as GO_IF_LEGITIMATE_ADDRESS.  */
        !           795: int
        !           796: sparc_address_cost (X)
        !           797:      rtx X;
        !           798: {
        !           799: #if 0
        !           800:   /* Handled before calling here.  */
        !           801:   if (GET_CODE (X) == REG)
        !           802:     { return 1; }
        !           803: #endif
        !           804:   if (GET_CODE (X) == PLUS)
        !           805:     {
        !           806:       if (GET_CODE (XEXP (X, 0)) == REG
        !           807:          && GET_CODE (XEXP (X, 1)) == REG)
        !           808:        return 2;
        !           809:       return 1;
        !           810:     }
        !           811:   else if (GET_CODE (X) == LO_SUM)
        !           812:     return 1;
        !           813:   else if (GET_CODE (X) == HIGH)
        !           814:     return 2;
        !           815:   return 4;
        !           816: }
        !           817: 
        !           818: /* Emit insns to move operands[1] into operands[0].
        !           819: 
        !           820:    Return 1 if we have written out everything that needs to be done to
        !           821:    do the move.  Otherwise, return 0 and the caller will emit the move
        !           822:    normally.
        !           823: 
        !           824:    SCRATCH_REG if non zero can be used as a scratch register for the move
        !           825:    operation.  It is provided by a SECONDARY_RELOAD_* macro if needed.  */
        !           826: 
        !           827: int
        !           828: emit_move_sequence (operands, mode, scratch_reg)
        !           829:      rtx *operands;
        !           830:      enum machine_mode mode;
        !           831:      rtx scratch_reg;
        !           832: {
        !           833:   register rtx operand0 = operands[0];
        !           834:   register rtx operand1 = operands[1];
        !           835: 
        !           836:   /* Handle most common case first: storing into a register.  */
        !           837:   if (register_operand (operand0, mode))
        !           838:     {
        !           839:       if (register_operand (operand1, mode)
        !           840:          || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
        !           841:          || (GET_CODE (operand1) == CONST_DOUBLE
        !           842:              && arith_double_operand (operand1, DImode))
        !           843:          || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode)
        !           844:          /* Only `general_operands' can come here, so MEM is ok.  */
        !           845:          || GET_CODE (operand1) == MEM)
        !           846:        {
        !           847:          /* Run this case quickly.  */
        !           848:          emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
        !           849:          return 1;
        !           850:        }
        !           851:     }
        !           852:   else if (GET_CODE (operand0) == MEM)
        !           853:     {
        !           854:       if (register_operand (operand1, mode) || operand1 == const0_rtx)
        !           855:        {
        !           856:          /* Run this case quickly.  */
        !           857:          emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
        !           858:          return 1;
        !           859:        }
        !           860:       if (! reload_in_progress)
        !           861:        {
        !           862:          operands[0] = validize_mem (operand0);
        !           863:          operands[1] = operand1 = force_reg (mode, operand1);
        !           864:        }
        !           865:     }
        !           866: 
        !           867:   /* Simplify the source if we need to.  Must handle DImode HIGH operators
        !           868:      here because such a move needs a clobber added.  */
        !           869:   if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
        !           870:       || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode))
        !           871:     {
        !           872:       if (flag_pic && symbolic_operand (operand1, mode))
        !           873:        {
        !           874:          rtx temp_reg = reload_in_progress ? operand0 : 0;
        !           875: 
        !           876:          operands[1] = legitimize_pic_address (operand1, mode, temp_reg,
        !           877:                                                scratch_reg);
        !           878:        }
        !           879:       else if (GET_CODE (operand1) == CONST_INT
        !           880:               ? (! SMALL_INT (operand1)
        !           881:                  && (INTVAL (operand1) & 0x3ff) != 0)
        !           882:               : (GET_CODE (operand1) == CONST_DOUBLE
        !           883:                  ? ! arith_double_operand (operand1, DImode)
        !           884:                  : 1))
        !           885:        {
        !           886:          /* For DImode values, temp must be operand0 because of the way
        !           887:             HI and LO_SUM work.  The LO_SUM operator only copies half of
        !           888:             the LSW from the dest of the HI operator.  If the LO_SUM dest is
        !           889:             not the same as the HI dest, then the MSW of the LO_SUM dest will
        !           890:             never be set.
        !           891: 
        !           892:             ??? The real problem here is that the ...(HI:DImode pattern emits
        !           893:             multiple instructions, and the ...(LO_SUM:DImode pattern emits
        !           894:             one instruction.  This fails, because the compiler assumes that
        !           895:             LO_SUM copies all bits of the first operand to its dest.  Better
        !           896:             would be to have the HI pattern emit one instruction and the
        !           897:             LO_SUM pattern multiple instructions.  Even better would be
        !           898:             to use four rtl insns.  */
        !           899:          rtx temp = ((reload_in_progress || mode == DImode)
        !           900:                      ? operand0 : gen_reg_rtx (mode));
        !           901: 
        !           902:          emit_insn (gen_rtx (SET, VOIDmode, temp,
        !           903:                              gen_rtx (HIGH, mode, operand1)));
        !           904:          operands[1] = gen_rtx (LO_SUM, mode, temp, operand1);
        !           905:        }
        !           906:     }
        !           907: 
        !           908:   if (GET_CODE (operand1) == LABEL_REF && flag_pic)
        !           909:     {
        !           910:       /* The procedure for doing this involves using a call instruction to
        !           911:         get the pc into o7.  We need to indicate this explicitly because
        !           912:         the tablejump pattern assumes that it can use this value also.  */
        !           913:       emit_insn (gen_rtx (PARALLEL, VOIDmode,
        !           914:                          gen_rtvec (2,
        !           915:                                     gen_rtx (SET, VOIDmode, operand0,
        !           916:                                              operand1),
        !           917:                                     gen_rtx (SET, VOIDmode,
        !           918:                                              gen_rtx (REG, mode, 15),
        !           919:                                              pc_rtx))));
        !           920:       return 1;
        !           921:     }
        !           922: 
        !           923:   /* Now have insn-emit do whatever it normally does.  */
        !           924:   return 0;
        !           925: }
        !           926: 
        !           927: /* Return the best assembler insn template
        !           928:    for moving operands[1] into operands[0] as a fullword.  */
        !           929: 
        !           930: char *
        !           931: singlemove_string (operands)
        !           932:      rtx *operands;
        !           933: {
        !           934:   if (GET_CODE (operands[0]) == MEM)
        !           935:     {
        !           936:       if (GET_CODE (operands[1]) != MEM)
        !           937:        return "st %r1,%0";
        !           938:       else
        !           939:        abort ();
        !           940:     }
        !           941:   if (GET_CODE (operands[1]) == MEM)
        !           942:     return "ld %1,%0";
        !           943:   if (GET_CODE (operands[1]) == CONST_INT
        !           944:       && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
        !           945:     {
        !           946:       int i = INTVAL (operands[1]);
        !           947: 
        !           948:       /* If all low order 12 bits are clear, then we only need a single
        !           949:         sethi insn to load the constant.  */
        !           950:       if (i & 0x00000FFF)
        !           951:        return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
        !           952:       else
        !           953:        return "sethi %%hi(%a1),%0";
        !           954:     }
        !           955:   /* ??? Wrong if target is DImode?  */
        !           956:   return "mov %1,%0";
        !           957: }
        !           958: 
        !           959: /* Output assembler code to perform a doubleword move insn
        !           960:    with operands OPERANDS.  */
        !           961: 
        !           962: char *
        !           963: output_move_double (operands)
        !           964:      rtx *operands;
        !           965: {
        !           966:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
        !           967:   rtx latehalf[2];
        !           968:   rtx addreg0 = 0, addreg1 = 0;
        !           969: 
        !           970:   /* First classify both operands.  */
        !           971: 
        !           972:   if (REG_P (operands[0]))
        !           973:     optype0 = REGOP;
        !           974:   else if (offsettable_memref_p (operands[0]))
        !           975:     optype0 = OFFSOP;
        !           976:   else if (GET_CODE (operands[0]) == MEM)
        !           977:     optype0 = MEMOP;
        !           978:   else
        !           979:     optype0 = RNDOP;
        !           980: 
        !           981:   if (REG_P (operands[1]))
        !           982:     optype1 = REGOP;
        !           983:   else if (CONSTANT_P (operands[1]))
        !           984:     optype1 = CNSTOP;
        !           985:   else if (offsettable_memref_p (operands[1]))
        !           986:     optype1 = OFFSOP;
        !           987:   else if (GET_CODE (operands[1]) == MEM)
        !           988:     optype1 = MEMOP;
        !           989:   else
        !           990:     optype1 = RNDOP;
        !           991: 
        !           992:   /* Check for the cases that the operand constraints are not
        !           993:      supposed to allow to happen.  Abort if we get one,
        !           994:      because generating code for these cases is painful.  */
        !           995: 
        !           996:   if (optype0 == RNDOP || optype1 == RNDOP)
        !           997:     abort ();
        !           998: 
        !           999:   /* If an operand is an unoffsettable memory ref, find a register
        !          1000:      we can increment temporarily to make it refer to the second word.  */
        !          1001: 
        !          1002:   if (optype0 == MEMOP)
        !          1003:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
        !          1004: 
        !          1005:   if (optype1 == MEMOP)
        !          1006:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
        !          1007: 
        !          1008:   /* Ok, we can do one word at a time.
        !          1009:      Normally we do the low-numbered word first,
        !          1010:      but if either operand is autodecrementing then we
        !          1011:      do the high-numbered word first.
        !          1012: 
        !          1013:      In either case, set up in LATEHALF the operands to use for the
        !          1014:      high-numbered (least significant) word and in some cases alter the
        !          1015:      operands in OPERANDS to be suitable for the low-numbered word.  */
        !          1016: 
        !          1017:   if (optype0 == REGOP)
        !          1018:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
        !          1019:   else if (optype0 == OFFSOP)
        !          1020:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
        !          1021:   else
        !          1022:     latehalf[0] = operands[0];
        !          1023: 
        !          1024:   if (optype1 == REGOP)
        !          1025:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
        !          1026:   else if (optype1 == OFFSOP)
        !          1027:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
        !          1028:   else if (optype1 == CNSTOP)
        !          1029:     split_double (operands[1], &operands[1], &latehalf[1]);
        !          1030:   else
        !          1031:     latehalf[1] = operands[1];
        !          1032: 
        !          1033:   /* If the first move would clobber the source of the second one,
        !          1034:      do them in the other order.
        !          1035: 
        !          1036:      RMS says "This happens only for registers;
        !          1037:      such overlap can't happen in memory unless the user explicitly
        !          1038:      sets it up, and that is an undefined circumstance."
        !          1039: 
        !          1040:      but it happens on the sparc when loading parameter registers,
        !          1041:      so I am going to define that circumstance, and make it work
        !          1042:      as expected.  */
        !          1043: 
        !          1044:   /* Easy case: try moving both words at once.  */
        !          1045:   /* First check for moving between an even/odd register pair
        !          1046:      and a memory location.  */
        !          1047:   if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP
        !          1048:        && (REGNO (operands[0]) & 1) == 0)
        !          1049:       || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP
        !          1050:          && (REGNO (operands[1]) & 1) == 0))
        !          1051:     {
        !          1052:       rtx op1, op2;
        !          1053:       rtx base = 0, offset = const0_rtx;
        !          1054: 
        !          1055:       /* OP1 gets the register pair, and OP2 gets the memory address.  */
        !          1056:       if (optype0 == REGOP)
        !          1057:        op1 = operands[0], op2 = operands[1];
        !          1058:       else
        !          1059:        op1 = operands[1], op2 = operands[0];
        !          1060: 
        !          1061:       /* Now see if we can trust the address to be 8-byte aligned.  */
        !          1062:       /* Trust global variables.  */
        !          1063: 
        !          1064:       if (GET_CODE (op2) == LO_SUM)
        !          1065:        {
        !          1066:          operands[0] = op1;
        !          1067:          operands[1] = op2;
        !          1068: 
        !          1069:          if (final_sequence)
        !          1070:            abort ();
        !          1071:          return "ldd %1,%0";
        !          1072:        }
        !          1073: 
        !          1074:       if (GET_CODE (XEXP (op2, 0)) == PLUS)
        !          1075:        {
        !          1076:          rtx temp = XEXP (op2, 0);
        !          1077:          if (GET_CODE (XEXP (temp, 0)) == REG)
        !          1078:            base = XEXP (temp, 0), offset = XEXP (temp, 1);
        !          1079:          else if (GET_CODE (XEXP (temp, 1)) == REG)
        !          1080:            base = XEXP (temp, 1), offset = XEXP (temp, 0);
        !          1081:        }
        !          1082: 
        !          1083:       /* Trust round enough offsets from the stack or frame pointer.  */
        !          1084:       if (base
        !          1085:          && (REGNO (base) == FRAME_POINTER_REGNUM
        !          1086:              || REGNO (base) == STACK_POINTER_REGNUM))
        !          1087:        {
        !          1088:          if (GET_CODE (offset) == CONST_INT
        !          1089:              && (INTVAL (offset) & 0x7) == 0)
        !          1090:            {
        !          1091:              if (op1 == operands[0])
        !          1092:                return "ldd %1,%0";
        !          1093:              else
        !          1094:                return "std %1,%0";
        !          1095:            }
        !          1096:        }
        !          1097:       /* We know structs not on the stack are properly aligned.  Since a
        !          1098:         double asks for 8-byte alignment, we know it must have got that
        !          1099:         if it is in a struct.  But a DImode need not be 8-byte aligned,
        !          1100:         because it could be a struct containing two ints or pointers.  */
        !          1101:       else if (GET_CODE (operands[1]) == MEM
        !          1102:               && GET_MODE (operands[1]) == DFmode
        !          1103:               && (CONSTANT_P (XEXP (operands[1], 0))
        !          1104:                   /* Let user ask for it anyway.  */
        !          1105:                   || TARGET_ALIGN))
        !          1106:        return "ldd %1,%0";
        !          1107:       else if (GET_CODE (operands[0]) == MEM
        !          1108:               && GET_MODE (operands[0]) == DFmode
        !          1109:               && (CONSTANT_P (XEXP (operands[0], 0))
        !          1110:                   || TARGET_ALIGN))
        !          1111:        return "std %1,%0";
        !          1112:     }
        !          1113: 
        !          1114:   if (optype0 == REGOP && optype1 == REGOP
        !          1115:       && REGNO (operands[0]) == REGNO (latehalf[1]))
        !          1116:     {
        !          1117:       /* Make any unoffsettable addresses point at high-numbered word.  */
        !          1118:       if (addreg0)
        !          1119:        output_asm_insn ("add %0,0x4,%0", &addreg0);
        !          1120:       if (addreg1)
        !          1121:        output_asm_insn ("add %0,0x4,%0", &addreg1);
        !          1122: 
        !          1123:       /* Do that word.  */
        !          1124:       output_asm_insn (singlemove_string (latehalf), latehalf);
        !          1125: 
        !          1126:       /* Undo the adds we just did.  */
        !          1127:       if (addreg0)
        !          1128:        output_asm_insn ("add %0,-0x4,%0", &addreg0);
        !          1129:       if (addreg1)
        !          1130:        output_asm_insn ("add %0,-0x4,%0", &addreg1);
        !          1131: 
        !          1132:       /* Do low-numbered word.  */
        !          1133:       return singlemove_string (operands);
        !          1134:     }
        !          1135:   else if (optype0 == REGOP && optype1 != REGOP
        !          1136:           && reg_overlap_mentioned_p (operands[0], operands[1]))
        !          1137:     {
        !          1138:       /* Do the late half first.  */
        !          1139:       output_asm_insn (singlemove_string (latehalf), latehalf);
        !          1140:       /* Then clobber.  */
        !          1141:       return singlemove_string (operands);
        !          1142:     }
        !          1143: 
        !          1144:   /* Normal case: do the two words, low-numbered first.  */
        !          1145: 
        !          1146:   output_asm_insn (singlemove_string (operands), operands);
        !          1147: 
        !          1148:   /* Make any unoffsettable addresses point at high-numbered word.  */
        !          1149:   if (addreg0)
        !          1150:     output_asm_insn ("add %0,0x4,%0", &addreg0);
        !          1151:   if (addreg1)
        !          1152:     output_asm_insn ("add %0,0x4,%0", &addreg1);
        !          1153: 
        !          1154:   /* Do that word.  */
        !          1155:   output_asm_insn (singlemove_string (latehalf), latehalf);
        !          1156: 
        !          1157:   /* Undo the adds we just did.  */
        !          1158:   if (addreg0)
        !          1159:     output_asm_insn ("add %0,-0x4,%0", &addreg0);
        !          1160:   if (addreg1)
        !          1161:     output_asm_insn ("add %0,-0x4,%0", &addreg1);
        !          1162: 
        !          1163:   return "";
        !          1164: }
        !          1165: 
        !          1166: char *
        !          1167: output_fp_move_double (operands)
        !          1168:      rtx *operands;
        !          1169: {
        !          1170:   rtx addr;
        !          1171: 
        !          1172:   if (FP_REG_P (operands[0]))
        !          1173:     {
        !          1174:       if (FP_REG_P (operands[1]))
        !          1175:        return "fmovs %1,%0\n\tfmovs %R1,%R0";
        !          1176:       if (GET_CODE (operands[1]) == REG)
        !          1177:        {
        !          1178:          if ((REGNO (operands[1]) & 1) == 0)
        !          1179:            return "std %1,[%@-8]\n\tldd [%@-8],%0";
        !          1180:          else
        !          1181:            return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0";
        !          1182:        }
        !          1183:       addr = XEXP (operands[1], 0);
        !          1184: 
        !          1185:       /* Use ldd if known to be aligned.  */
        !          1186:       if (TARGET_ALIGN
        !          1187:          || (GET_CODE (addr) == PLUS
        !          1188:              && (((XEXP (addr, 0) == frame_pointer_rtx
        !          1189:                    || XEXP (addr, 0) == stack_pointer_rtx)
        !          1190:                   && GET_CODE (XEXP (addr, 1)) == CONST_INT
        !          1191:                   && (INTVAL (XEXP (addr, 1)) & 0x7) == 0)
        !          1192:                  /* Arrays are known to be aligned,
        !          1193:                     and reg+reg addresses are used (on this machine)
        !          1194:                     only for array accesses.  */
        !          1195:                  || (REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1)))))
        !          1196:          || (GET_MODE (operands[0]) == DFmode
        !          1197:              && (GET_CODE (addr) == LO_SUM || CONSTANT_P (addr))))
        !          1198:        return "ldd %1,%0";
        !          1199: 
        !          1200:       /* Otherwise use two ld insns.  */
        !          1201:       operands[2]
        !          1202:        = gen_rtx (MEM, GET_MODE (operands[1]),
        !          1203:                   plus_constant_for_output (addr, 4));
        !          1204:        return "ld %1,%0\n\tld %2,%R0";
        !          1205:     }
        !          1206:   else if (FP_REG_P (operands[1]))
        !          1207:     {
        !          1208:       if (GET_CODE (operands[0]) == REG)
        !          1209:        {
        !          1210:          if ((REGNO (operands[0]) & 1) == 0)
        !          1211:            return "std %1,[%@-8]\n\tldd [%@-8],%0";
        !          1212:          else
        !          1213:            return "std %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0";
        !          1214:        }
        !          1215:       addr = XEXP (operands[0], 0);
        !          1216: 
        !          1217:       /* Use std if we can be sure it is well-aligned.  */
        !          1218:       if (TARGET_ALIGN
        !          1219:          || (GET_CODE (addr) == PLUS
        !          1220:              && (((XEXP (addr, 0) == frame_pointer_rtx
        !          1221:                    || XEXP (addr, 0) == stack_pointer_rtx)
        !          1222:                   && GET_CODE (XEXP (addr, 1)) == CONST_INT
        !          1223:                   && (INTVAL (XEXP (addr, 1)) & 0x7) == 0)
        !          1224:                  /* Arrays are known to be aligned,
        !          1225:                     and reg+reg addresses are used (on this machine)
        !          1226:                     only for array accesses.  */
        !          1227:                  || (REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1)))))
        !          1228:          || (GET_MODE (operands[1]) == DFmode
        !          1229:              && (GET_CODE (addr) == LO_SUM || CONSTANT_P (addr))))
        !          1230:        return "std %1,%0";
        !          1231: 
        !          1232:       /* Otherwise use two st insns.  */
        !          1233:       operands[2]
        !          1234:        = gen_rtx (MEM, GET_MODE (operands[0]),
        !          1235:                   plus_constant_for_output (addr, 4));
        !          1236:       return "st %r1,%0\n\tst %R1,%2";
        !          1237:     }
        !          1238:   else abort ();
        !          1239: }
        !          1240: 
        !          1241: /* Return a REG that occurs in ADDR with coefficient 1.
        !          1242:    ADDR can be effectively incremented by incrementing REG.  */
        !          1243: 
        !          1244: static rtx
        !          1245: find_addr_reg (addr)
        !          1246:      rtx addr;
        !          1247: {
        !          1248:   while (GET_CODE (addr) == PLUS)
        !          1249:     {
        !          1250:       /* We absolutely can not fudge the frame pointer here, because the
        !          1251:         frame pointer must always be 8 byte aligned.  It also confuses
        !          1252:         debuggers.  */
        !          1253:       if (GET_CODE (XEXP (addr, 0)) == REG
        !          1254:          && REGNO (XEXP (addr, 0)) != FRAME_POINTER_REGNUM)
        !          1255:        addr = XEXP (addr, 0);
        !          1256:       else if (GET_CODE (XEXP (addr, 1)) == REG
        !          1257:               && REGNO (XEXP (addr, 1)) != FRAME_POINTER_REGNUM)
        !          1258:        addr = XEXP (addr, 1);
        !          1259:       else if (CONSTANT_P (XEXP (addr, 0)))
        !          1260:        addr = XEXP (addr, 1);
        !          1261:       else if (CONSTANT_P (XEXP (addr, 1)))
        !          1262:        addr = XEXP (addr, 0);
        !          1263:       else
        !          1264:        abort ();
        !          1265:     }
        !          1266:   if (GET_CODE (addr) == REG)
        !          1267:     return addr;
        !          1268:   abort ();
        !          1269: }
        !          1270: 
        !          1271: void
        !          1272: output_sized_memop (opname, mode, signedp)
        !          1273:      char *opname;
        !          1274:      enum machine_mode mode;
        !          1275:      int signedp;
        !          1276: {
        !          1277:   static char *ld_size_suffix_u[] = { "ub", "uh", "", "?", "d" };
        !          1278:   static char *ld_size_suffix_s[] = { "sb", "sh", "", "?", "d" };
        !          1279:   static char *st_size_suffix[] = { "b", "h", "", "?", "d" };
        !          1280:   char **opnametab, *modename;
        !          1281: 
        !          1282:   if (opname[0] == 'l')
        !          1283:     if (signedp)
        !          1284:       opnametab = ld_size_suffix_s;
        !          1285:     else
        !          1286:       opnametab = ld_size_suffix_u;
        !          1287:   else
        !          1288:     opnametab = st_size_suffix;
        !          1289:   modename = opnametab[GET_MODE_SIZE (mode) >> 1];
        !          1290: 
        !          1291:   fprintf (asm_out_file, "\t%s%s", opname, modename);
        !          1292: }
        !          1293: 
        !          1294: void
        !          1295: output_move_with_extension (operands)
        !          1296:      rtx *operands;
        !          1297: {
        !          1298:   if (GET_MODE (operands[2]) == HImode)
        !          1299:     output_asm_insn ("sll %2,0x10,%0", operands);
        !          1300:   else if (GET_MODE (operands[2]) == QImode)
        !          1301:     output_asm_insn ("sll %2,0x18,%0", operands);
        !          1302:   else
        !          1303:     abort ();
        !          1304: }
        !          1305: 
        !          1306: /* Load the address specified by OPERANDS[3] into the register
        !          1307:    specified by OPERANDS[0].
        !          1308: 
        !          1309:    OPERANDS[3] may be the result of a sum, hence it could either be:
        !          1310: 
        !          1311:    (1) CONST
        !          1312:    (2) REG
        !          1313:    (2) REG + CONST_INT
        !          1314:    (3) REG + REG + CONST_INT
        !          1315:    (4) REG + REG  (special case of 3).
        !          1316: 
        !          1317:    Note that (3) is not a legitimate address.
        !          1318:    All cases are handled here.  */
        !          1319: 
        !          1320: void
        !          1321: output_load_address (operands)
        !          1322:      rtx *operands;
        !          1323: {
        !          1324:   rtx base, offset;
        !          1325: 
        !          1326:   if (CONSTANT_P (operands[3]))
        !          1327:     {
        !          1328:       output_asm_insn ("set %3,%0", operands);
        !          1329:       return;
        !          1330:     }
        !          1331: 
        !          1332:   if (REG_P (operands[3]))
        !          1333:     {
        !          1334:       if (REGNO (operands[0]) != REGNO (operands[3]))
        !          1335:        output_asm_insn ("mov %3,%0", operands);
        !          1336:       return;
        !          1337:     }
        !          1338: 
        !          1339:   if (GET_CODE (operands[3]) != PLUS)
        !          1340:     abort ();
        !          1341: 
        !          1342:   base = XEXP (operands[3], 0);
        !          1343:   offset = XEXP (operands[3], 1);
        !          1344: 
        !          1345:   if (GET_CODE (base) == CONST_INT)
        !          1346:     {
        !          1347:       rtx tmp = base;
        !          1348:       base = offset;
        !          1349:       offset = tmp;
        !          1350:     }
        !          1351: 
        !          1352:   if (GET_CODE (offset) != CONST_INT)
        !          1353:     {
        !          1354:       /* Operand is (PLUS (REG) (REG)).  */
        !          1355:       base = operands[3];
        !          1356:       offset = const0_rtx;
        !          1357:     }
        !          1358: 
        !          1359:   if (REG_P (base))
        !          1360:     {
        !          1361:       operands[6] = base;
        !          1362:       operands[7] = offset;
        !          1363:       if (SMALL_INT (offset))
        !          1364:        output_asm_insn ("add %6,%7,%0", operands);
        !          1365:       else
        !          1366:        output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
        !          1367:     }
        !          1368:   else if (GET_CODE (base) == PLUS)
        !          1369:     {
        !          1370:       operands[6] = XEXP (base, 0);
        !          1371:       operands[7] = XEXP (base, 1);
        !          1372:       operands[8] = offset;
        !          1373: 
        !          1374:       if (SMALL_INT (offset))
        !          1375:        output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
        !          1376:       else
        !          1377:        output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
        !          1378:     }
        !          1379:   else
        !          1380:     abort ();
        !          1381: }
        !          1382: 
        !          1383: /* Output code to place a size count SIZE in register REG.
        !          1384:    ALIGN is the size of the unit of transfer.
        !          1385: 
        !          1386:    Because block moves are pipelined, we don't include the
        !          1387:    first element in the transfer of SIZE to REG.  */
        !          1388: 
        !          1389: static void
        !          1390: output_size_for_block_move (size, reg, align)
        !          1391:      rtx size, reg;
        !          1392:      rtx align;
        !          1393: {
        !          1394:   rtx xoperands[3];
        !          1395: 
        !          1396:   xoperands[0] = reg;
        !          1397:   xoperands[1] = size;
        !          1398:   xoperands[2] = align;
        !          1399:   if (GET_CODE (size) == REG)
        !          1400:     output_asm_insn ("sub %1,%2,%0", xoperands);
        !          1401:   else
        !          1402:     {
        !          1403:       xoperands[1]
        !          1404:        = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
        !          1405:       output_asm_insn ("set %1,%0", xoperands);
        !          1406:     }
        !          1407: }
        !          1408: 
        !          1409: /* Emit code to perform a block move.
        !          1410: 
        !          1411:    OPERANDS[0] is the destination.
        !          1412:    OPERANDS[1] is the source.
        !          1413:    OPERANDS[2] is the size.
        !          1414:    OPERANDS[3] is the alignment safe to use.
        !          1415:    OPERANDS[4] is a register we can safely clobber as a temp.  */
        !          1416: 
        !          1417: char *
        !          1418: output_block_move (operands)
        !          1419:      rtx *operands;
        !          1420: {
        !          1421:   /* A vector for our computed operands.  Note that load_output_address
        !          1422:      makes use of (and can clobber) up to the 8th element of this vector.  */
        !          1423:   rtx xoperands[10];
        !          1424:   rtx zoperands[10];
        !          1425:   static int movstrsi_label = 0;
        !          1426:   int i;
        !          1427:   rtx temp1 = operands[4];
        !          1428:   rtx sizertx = operands[2];
        !          1429:   rtx alignrtx = operands[3];
        !          1430:   int align = INTVAL (alignrtx);
        !          1431: 
        !          1432:   xoperands[0] = operands[0];
        !          1433:   xoperands[1] = operands[1];
        !          1434:   xoperands[2] = temp1;
        !          1435: 
        !          1436:   /* We can't move more than this many bytes at a time
        !          1437:      because we have only one register to move them through.  */
        !          1438:   if (align > GET_MODE_SIZE (GET_MODE (temp1)))
        !          1439:     {
        !          1440:       align = GET_MODE_SIZE (GET_MODE (temp1));
        !          1441:       alignrtx = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (temp1)));
        !          1442:     }
        !          1443: 
        !          1444:   /* If the size isn't known to be a multiple of the alignment,
        !          1445:      we have to do it in smaller pieces.  If we could determine that
        !          1446:      the size was a multiple of 2 (or whatever), we could be smarter
        !          1447:      about this.  */
        !          1448:   if (GET_CODE (sizertx) != CONST_INT)
        !          1449:     align = 1;
        !          1450:   else
        !          1451:     {
        !          1452:       int size = INTVAL (sizertx);
        !          1453:       while (size % align)
        !          1454:        align >>= 1;
        !          1455:     }
        !          1456: 
        !          1457:   if (align != INTVAL (alignrtx))
        !          1458:     alignrtx = gen_rtx (CONST_INT, VOIDmode, align);
        !          1459: 
        !          1460:   /* Recognize special cases of block moves.  These occur
        !          1461:      when GNU C++ is forced to treat something as BLKmode
        !          1462:      to keep it in memory, when its mode could be represented
        !          1463:      with something smaller.
        !          1464: 
        !          1465:      We cannot do this for global variables, since we don't know
        !          1466:      what pages they don't cross.  Sigh.  */
        !          1467:   if (GET_CODE (sizertx) == CONST_INT && INTVAL (sizertx) <= 16)
        !          1468:     {
        !          1469:       int size = INTVAL (sizertx);
        !          1470: 
        !          1471:       if (align == 1)
        !          1472:        {
        !          1473:          if (memory_address_p (QImode,
        !          1474:                                plus_constant_for_output (xoperands[0], size))
        !          1475:              && memory_address_p (QImode,
        !          1476:                                   plus_constant_for_output (xoperands[1],
        !          1477:                                                             size)))
        !          1478:            {
        !          1479:              /* We will store different integers into this particular RTX.  */
        !          1480:              xoperands[2] = rtx_alloc (CONST_INT);
        !          1481:              PUT_MODE (xoperands[2], VOIDmode);
        !          1482:              for (i = size-1; i >= 0; i--)
        !          1483:                {
        !          1484:                  INTVAL (xoperands[2]) = i;
        !          1485:                  output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]",
        !          1486:                                   xoperands);
        !          1487:                }
        !          1488:              return "";
        !          1489:            }
        !          1490:        }
        !          1491:       else if (align == 2)
        !          1492:        {
        !          1493:          if (memory_address_p (HImode,
        !          1494:                                plus_constant_for_output (xoperands[0], size))
        !          1495:              && memory_address_p (HImode,
        !          1496:                                   plus_constant_for_output (xoperands[1],
        !          1497:                                                             size)))
        !          1498:            {
        !          1499:              /* We will store different integers into this particular RTX.  */
        !          1500:              xoperands[2] = rtx_alloc (CONST_INT);
        !          1501:              PUT_MODE (xoperands[2], VOIDmode);
        !          1502:              for (i = (size>>1)-1; i >= 0; i--)
        !          1503:                {
        !          1504:                  INTVAL (xoperands[2]) = i<<1;
        !          1505:                  output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]",
        !          1506:                                   xoperands);
        !          1507:                }
        !          1508:              return "";
        !          1509:            }
        !          1510:        }
        !          1511:       else
        !          1512:        {
        !          1513:          if (memory_address_p (SImode,
        !          1514:                                plus_constant_for_output (xoperands[0], size))
        !          1515:              && memory_address_p (SImode,
        !          1516:                                   plus_constant_for_output (xoperands[1],
        !          1517:                                                             size)))
        !          1518:            {
        !          1519:              /* We will store different integers into this particular RTX.  */
        !          1520:              xoperands[2] = rtx_alloc (CONST_INT);
        !          1521:              PUT_MODE (xoperands[2], VOIDmode);
        !          1522:              for (i = (size>>2)-1; i >= 0; i--)
        !          1523:                {
        !          1524:                  INTVAL (xoperands[2]) = i<<2;
        !          1525:                  output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]",
        !          1526:                                   xoperands);
        !          1527:                }
        !          1528:              return "";
        !          1529:            }
        !          1530:        }
        !          1531:     }
        !          1532: 
        !          1533:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
        !          1534:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
        !          1535:   xoperands[5] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
        !          1536: 
        !          1537:   /* This is the size of the transfer.
        !          1538:      Either use the register which already contains the size,
        !          1539:      or use a free register (used by no operands).
        !          1540:      Also emit code to decrement the size value by ALIGN.  */
        !          1541:   output_size_for_block_move (sizertx, temp1, alignrtx);
        !          1542: 
        !          1543:   /* Must handle the case when the size is zero or negative, so the first thing
        !          1544:      we do is compare the size against zero, and only copy bytes if it is
        !          1545:      zero or greater.  Note that we have already subtracted off the alignment
        !          1546:      once, so we must copy 1 alignment worth of bytes if the size is zero
        !          1547:      here.
        !          1548: 
        !          1549:      The SUN assembler complains about labels in branch delay slots, so we
        !          1550:      do this before outputing the load address, so that there will always
        !          1551:      be a harmless insn between the branch here and the next label emitted
        !          1552:      below.  */
        !          1553: 
        !          1554: #ifdef NO_UNDERSCORES
        !          1555:   output_asm_insn ("cmp %2,0\n\tbl .Lm%5", xoperands);
        !          1556: #else
        !          1557:   output_asm_insn ("cmp %2,0\n\tbl Lm%5", xoperands);
        !          1558: #endif
        !          1559: 
        !          1560:   zoperands[0] = operands[0];
        !          1561:   zoperands[3] = plus_constant_for_output (operands[0], align);
        !          1562:   output_load_address (zoperands);
        !          1563: 
        !          1564:   /* ??? This might be much faster if the loops below were preconditioned
        !          1565:      and unrolled.
        !          1566: 
        !          1567:      That is, at run time, copy enough bytes one at a time to ensure that the
        !          1568:      target and source addresses are aligned to the the largest possible
        !          1569:      alignment.  Then use a preconditioned unrolled loop to copy say 16
        !          1570:      bytes at a time.  Then copy bytes one at a time until finish the rest.  */
        !          1571: 
        !          1572:   /* Output the first label separately, so that it is spaced properly.  */
        !          1573: 
        !          1574: #ifdef NO_UNDERSCORES
        !          1575:   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, ".Lm", INTVAL (xoperands[3]));
        !          1576: #else
        !          1577:   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "Lm", INTVAL (xoperands[3]));
        !          1578: #endif
        !          1579: 
        !          1580: #ifdef NO_UNDERSCORES
        !          1581:   if (align == 1)
        !          1582:     output_asm_insn ("ldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tstb %%g1,[%0+%2]\n.Lm%5:", xoperands);
        !          1583:   else if (align == 2)
        !          1584:     output_asm_insn ("lduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tsth %%g1,[%0+%2]\n.Lm%5:", xoperands);
        !          1585:   else
        !          1586:     output_asm_insn ("ld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tst %%g1,[%0+%2]\n.Lm%5:", xoperands);
        !          1587:   return "";
        !          1588: #else
        !          1589:   if (align == 1)
        !          1590:     output_asm_insn ("ldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]\nLm%5:", xoperands);
        !          1591:   else if (align == 2)
        !          1592:     output_asm_insn ("lduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]\nLm%5:", xoperands);
        !          1593:   else
        !          1594:     output_asm_insn ("ld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]\nLm%5:", xoperands);
        !          1595:   return "";
        !          1596: #endif
        !          1597: }
        !          1598: 
        !          1599: /* Output reasonable peephole for set-on-condition-code insns.
        !          1600:    Note that these insns assume a particular way of defining
        !          1601:    labels.  Therefore, *both* sparc.h and this function must
        !          1602:    be changed if a new syntax is needed.    */
        !          1603: 
        !          1604: char *
        !          1605: output_scc_insn (operands, insn)
        !          1606:      rtx operands[];
        !          1607:      rtx insn;
        !          1608: {
        !          1609:   static char string[100];
        !          1610:   rtx label = 0, next = insn;
        !          1611:   int need_label = 0;
        !          1612: 
        !          1613:   /* Try doing a jump optimization which jump.c can't do for us
        !          1614:      because we did not expose that setcc works by using branches.
        !          1615: 
        !          1616:      If this scc insn is followed by an unconditional branch, then have
        !          1617:      the jump insn emitted here jump to that location, instead of to
        !          1618:      the end of the scc sequence as usual.  */
        !          1619: 
        !          1620:   do
        !          1621:     {
        !          1622:       if (GET_CODE (next) == CODE_LABEL)
        !          1623:        label = next;
        !          1624:       next = NEXT_INSN (next);
        !          1625:       if (next == 0)
        !          1626:        break;
        !          1627:     }
        !          1628:   while (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL);
        !          1629: 
        !          1630:   /* If we are in a sequence, and the following insn is a sequence also,
        !          1631:      then just following the current insn's next field will take us to the
        !          1632:      first insn of the next sequence, which is the wrong place.  We don't
        !          1633:      want to optimize with a branch that has had its delay slot filled.
        !          1634:      Avoid this by verifying that NEXT_INSN (PREV_INSN (next)) == next
        !          1635:      which fails only if NEXT is such a branch.  */
        !          1636: 
        !          1637:   if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next)
        !          1638:       && (! final_sequence || NEXT_INSN (PREV_INSN (next)) == next))
        !          1639:     label = JUMP_LABEL (next);
        !          1640:   /* If not optimizing, jump label fields are not set.  To be safe, always
        !          1641:      check here to whether label is still zero.  */
        !          1642:   if (label == 0)
        !          1643:     {
        !          1644:       label = gen_label_rtx ();
        !          1645:       need_label = 1;
        !          1646:     }
        !          1647: 
        !          1648:   LABEL_NUSES (label) += 1;
        !          1649: 
        !          1650:   operands[2] = label;
        !          1651: 
        !          1652:   /* If we are in a delay slot, assume it is the delay slot of an fpcc
        !          1653:      insn since our type isn't allowed anywhere else.  */
        !          1654: 
        !          1655:   /* ??? Fpcc instructions no longer have delay slots, so this code is
        !          1656:      probably obsolete.  */
        !          1657: 
        !          1658:   /* The fastest way to emit code for this is an annulled branch followed
        !          1659:      by two move insns.  This will take two cycles if the branch is taken,
        !          1660:      and three cycles if the branch is not taken.
        !          1661: 
        !          1662:      However, if we are in the delay slot of another branch, this won't work,
        !          1663:      because we can't put a branch in the delay slot of another branch.
        !          1664:      The above sequence would effectively take 3 or 4 cycles respectively
        !          1665:      since a no op would have be inserted between the two branches.
        !          1666:      In this case, we want to emit a move, annulled branch, and then the
        !          1667:      second move.  This sequence always takes 3 cycles, and hence is faster
        !          1668:      when we are in a branch delay slot.  */
        !          1669: 
        !          1670:   if (final_sequence)
        !          1671:     {
        !          1672:       strcpy (string, "mov 0,%0\n\t");
        !          1673:       strcat (string, output_cbranch (operands[1], 2, 0, 1, 0));
        !          1674:       strcat (string, "\n\tmov 1,%0");
        !          1675:     }
        !          1676:   else
        !          1677:     {
        !          1678:       strcpy (string, output_cbranch (operands[1], 2, 0, 1, 0));
        !          1679:       strcat (string, "\n\tmov 1,%0\n\tmov 0,%0");
        !          1680:     }
        !          1681: 
        !          1682:   if (need_label)
        !          1683:     strcat (string, "\n%l2:");
        !          1684: 
        !          1685:   return string;
        !          1686: }
        !          1687: 
        !          1688: /* Vectors to keep interesting information about registers where
        !          1689:    it can easily be got.  */
        !          1690: 
        !          1691: /* Modes for condition codes.  */
        !          1692: #define C_MODES                \
        !          1693:   ((1 << (int) CCmode) | (1 << (int) CC_NOOVmode) | (1 << (int) CCFPmode))
        !          1694: 
        !          1695: /* Modes for single-word (and smaller) quantities.  */
        !          1696: #define S_MODES                                                \
        !          1697:  (~C_MODES                                             \
        !          1698:   & ~ ((1 << (int) DImode) | (1 << (int) TImode)       \
        !          1699:       | (1 << (int) DFmode) | (1 << (int) TFmode)))
        !          1700: 
        !          1701: /* Modes for double-word (and smaller) quantities.  */
        !          1702: #define D_MODES                                        \
        !          1703:   (~C_MODES                                    \
        !          1704:    & ~ ((1 << (int) TImode) | (1 << (int) TFmode)))
        !          1705: 
        !          1706: /* Modes for quad-word quantities.  */
        !          1707: #define T_MODES (~C_MODES)
        !          1708: 
        !          1709: /* Modes for single-float quantities.  */
        !          1710: #define SF_MODES ((1 << (int) SFmode))
        !          1711: 
        !          1712: /* Modes for double-float quantities.  */
        !          1713: #define DF_MODES (SF_MODES | (1 << (int) DFmode) | (1 << (int) SCmode))
        !          1714: 
        !          1715: /* Modes for quad-float quantities.  */
        !          1716: #define TF_MODES (DF_MODES | (1 << (int) TFmode) | (1 << (int) DCmode))
        !          1717: 
        !          1718: /* Value is 1 if register/mode pair is acceptable on sparc.
        !          1719:    The funny mixture of D and T modes is because integer operations
        !          1720:    do not specially operate on tetra quantities, so non-quad-aligned
        !          1721:    registers can hold quadword quantities (except %o4 and %i4 because
        !          1722:    they cross fixed registers.  */
        !          1723: 
        !          1724: int hard_regno_mode_ok[] = {
        !          1725:   C_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
        !          1726:   T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
        !          1727:   T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
        !          1728:   T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
        !          1729: 
        !          1730:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
        !          1731:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
        !          1732:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
        !          1733:   TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES};
        !          1734: 
        !          1735: #ifdef __GNUC__
        !          1736: inline
        !          1737: #endif
        !          1738: static int
        !          1739: save_regs (file, low, high, base, offset, n_fregs)
        !          1740:      FILE *file;
        !          1741:      int low, high;
        !          1742:      char *base;
        !          1743:      int offset;
        !          1744:      int n_fregs;
        !          1745: {
        !          1746:   int i;
        !          1747: 
        !          1748:   for (i = low; i < high; i += 2)
        !          1749:     {
        !          1750:       if (regs_ever_live[i] && ! call_used_regs[i])
        !          1751:        if (regs_ever_live[i+1] && ! call_used_regs[i+1])
        !          1752:          fprintf (file, "\tstd %s,[%s+%d]\n",
        !          1753:                   reg_names[i], base, offset + 4 * n_fregs),
        !          1754:          n_fregs += 2;
        !          1755:        else
        !          1756:          fprintf (file, "\tst %s,[%s+%d]\n",
        !          1757:                   reg_names[i], base, offset + 4 * n_fregs),
        !          1758:          n_fregs += 2;
        !          1759:       else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
        !          1760:        fprintf (file, "\tst %s,[%s+%d]\n",
        !          1761:                 reg_names[i+1], base, offset + 4 * n_fregs),
        !          1762:        n_fregs += 2;
        !          1763:     }
        !          1764:   return n_fregs;
        !          1765: }
        !          1766: 
        !          1767: #ifdef __GNUC__
        !          1768: inline
        !          1769: #endif
        !          1770: static int
        !          1771: restore_regs (file, low, high, base, offset, n_fregs)
        !          1772:      FILE *file;
        !          1773:      int low, high;
        !          1774:      char *base;
        !          1775:      int offset;
        !          1776: {
        !          1777:   int i;
        !          1778: 
        !          1779:   for (i = low; i < high; i += 2)
        !          1780:     {
        !          1781:       if (regs_ever_live[i] && ! call_used_regs[i])
        !          1782:        if (regs_ever_live[i+1] && ! call_used_regs[i+1])
        !          1783:          fprintf (file, "\tldd [%s+%d], %s\n",
        !          1784:                   base, offset + 4 * n_fregs, reg_names[i]),
        !          1785:          n_fregs += 2;
        !          1786:        else
        !          1787:          fprintf (file, "\tld [%s+%d],%s\n",
        !          1788:                   base, offset + 4 * n_fregs, reg_names[i]),
        !          1789:          n_fregs += 2;
        !          1790:       else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
        !          1791:        fprintf (file, "\tld [%s+%d],%s\n",
        !          1792:                 base, offset + 4 * n_fregs, reg_names[i+1]),
        !          1793:        n_fregs += 2;
        !          1794:     }
        !          1795:   return n_fregs;
        !          1796: }
        !          1797: 
        !          1798: /* Static variables we want to share between prologue and epilogue.  */
        !          1799: 
        !          1800: /* Number of live floating point registers needed to be saved.  */
        !          1801: static int num_fregs;
        !          1802: 
        !          1803: /* Nonzero if any floating point register was ever used.  */
        !          1804: static int fregs_ever_live;
        !          1805: 
        !          1806: int
        !          1807: compute_frame_size (size, leaf_function)
        !          1808:      int size;
        !          1809:      int leaf_function;
        !          1810: {
        !          1811:   int fregs_ever_live = 0;
        !          1812:   int n_fregs = 0, i;
        !          1813:   int outgoing_args_size = (current_function_outgoing_args_size
        !          1814:                            + REG_PARM_STACK_SPACE (current_function_decl));
        !          1815: 
        !          1816:   apparent_fsize = ((size) + 7 - STARTING_FRAME_OFFSET) & -8;
        !          1817:   for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2)
        !          1818:     fregs_ever_live |= regs_ever_live[i]|regs_ever_live[i+1];
        !          1819: 
        !          1820:   if (TARGET_EPILOGUE && fregs_ever_live)
        !          1821:     {
        !          1822:       for (i = 32; i < FIRST_PSEUDO_REGISTER; i += 2)
        !          1823:        if ((regs_ever_live[i] && ! call_used_regs[i])
        !          1824:            || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
        !          1825:          n_fregs += 2;
        !          1826:     }
        !          1827: 
        !          1828:   /* Set up values for use in `function_epilogue'.  */
        !          1829:   num_fregs = n_fregs;
        !          1830: 
        !          1831:   apparent_fsize += (outgoing_args_size+7) & -8;
        !          1832:   if (leaf_function && n_fregs == 0
        !          1833:       && apparent_fsize == (REG_PARM_STACK_SPACE (current_function_decl)
        !          1834:                            - STARTING_FRAME_OFFSET))
        !          1835:     apparent_fsize = 0;
        !          1836: 
        !          1837:   actual_fsize = apparent_fsize + n_fregs*4;
        !          1838: 
        !          1839:   /* Make sure nothing can clobber our register windows.
        !          1840:      If a SAVE must be done, or there is a stack-local variable,
        !          1841:      the register window area must be allocated.  */
        !          1842:   if (leaf_function == 0 || size > 0)
        !          1843:     actual_fsize += (16 * UNITS_PER_WORD)+8;
        !          1844: 
        !          1845:   return actual_fsize;
        !          1846: }
        !          1847: 
        !          1848: void
        !          1849: output_function_prologue (file, size, leaf_function)
        !          1850:      FILE *file;
        !          1851:      int size;
        !          1852: {
        !          1853:   if (leaf_function)
        !          1854:     frame_base_name = "%sp+80";
        !          1855:   else
        !          1856:     frame_base_name = "%fp";
        !          1857: 
        !          1858:   actual_fsize = compute_frame_size (size, leaf_function);
        !          1859: 
        !          1860:   fprintf (file, "\t!#PROLOGUE# 0\n");
        !          1861:   if (actual_fsize == 0) /* do nothing.  */ ;
        !          1862:   else if (actual_fsize < 4096)
        !          1863:     {
        !          1864:       if (! leaf_function)
        !          1865:        fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize);
        !          1866:       else
        !          1867:        fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize);
        !          1868:     }
        !          1869:   else if (! leaf_function)
        !          1870:     {
        !          1871:       /* Need to use actual_fsize, since we are also allocating space for
        !          1872:         our callee (and our own register save area).  */
        !          1873:       fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n",
        !          1874:               -actual_fsize, -actual_fsize);
        !          1875:       fprintf (file, "\tsave %%sp,%%g1,%%sp\n");
        !          1876:     }
        !          1877:   else
        !          1878:     {
        !          1879:       /* Put pointer to parameters into %g4, and allocate
        !          1880:         frame space using result computed into %g1.  actual_fsize
        !          1881:         used instead of apparent_fsize for reasons stated above.  */
        !          1882:       abort ();
        !          1883: 
        !          1884:       fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n",
        !          1885:               -actual_fsize, -actual_fsize);
        !          1886:       fprintf (file, "\tadd %%sp,64,%%g4\n\tadd %%sp,%%g1,%%sp\n");
        !          1887:     }
        !          1888: 
        !          1889:   /* If doing anything with PIC, do it now.  */
        !          1890:   if (! flag_pic)
        !          1891:     fprintf (file, "\t!#PROLOGUE# 1\n");
        !          1892: 
        !          1893:   /* Figure out where to save any special registers.  */
        !          1894:   if (num_fregs)
        !          1895:     {
        !          1896:       int offset, n_fregs = num_fregs;
        !          1897: 
        !          1898:       if (! leaf_function)
        !          1899:        offset = -apparent_fsize;
        !          1900:       else
        !          1901:        offset = 0;
        !          1902: 
        !          1903:       if (TARGET_EPILOGUE && ! leaf_function)
        !          1904:        n_fregs = save_regs (file, 0, 16, frame_base_name, offset, 0);
        !          1905:       else if (leaf_function)
        !          1906:        n_fregs = save_regs (file, 0, 32, frame_base_name, offset, 0);
        !          1907:       if (TARGET_EPILOGUE)
        !          1908:        save_regs (file, 32, FIRST_PSEUDO_REGISTER,
        !          1909:                   frame_base_name, offset, n_fregs);
        !          1910:     }
        !          1911: 
        !          1912:   if (regs_ever_live[62])
        !          1913:     fprintf (file, "\tst %s,[%s-16]\n\tst %s,[%s-12]\n",
        !          1914:             reg_names[0], frame_base_name,
        !          1915:             reg_names[0], frame_base_name);
        !          1916: 
        !          1917:   leaf_label = 0;
        !          1918:   if (leaf_function && actual_fsize != 0)
        !          1919:     {
        !          1920:       /* warning ("leaf procedure with frame size %d", actual_fsize); */
        !          1921:       if (! TARGET_EPILOGUE)
        !          1922:        leaf_label = gen_label_rtx ();
        !          1923:     }
        !          1924: }
        !          1925: 
        !          1926: void
        !          1927: output_function_epilogue (file, size, leaf_function, true_epilogue)
        !          1928:      FILE *file;
        !          1929:      int size;
        !          1930: {
        !          1931:   int n_fregs, i;
        !          1932:   char *ret;
        !          1933: 
        !          1934:   if (leaf_label)
        !          1935:     {
        !          1936:       if (leaf_function < 0)
        !          1937:        abort ();
        !          1938:       emit_label_after (leaf_label, get_last_insn ());
        !          1939:       final_scan_insn (get_last_insn (), file, 0, 0, 1);
        !          1940:     }
        !          1941: 
        !          1942:   if (num_fregs)
        !          1943:     {
        !          1944:       int offset, n_fregs = num_fregs;
        !          1945: 
        !          1946:       if (! leaf_function)
        !          1947:        offset = -apparent_fsize;
        !          1948:       else
        !          1949:        offset = 0;
        !          1950: 
        !          1951:       if (TARGET_EPILOGUE && ! leaf_function)
        !          1952:        n_fregs = restore_regs (file, 0, 16, frame_base_name, offset, 0);
        !          1953:       else if (leaf_function)
        !          1954:        n_fregs = restore_regs (file, 0, 32, frame_base_name, offset, 0);
        !          1955:       if (TARGET_EPILOGUE)
        !          1956:        restore_regs (file, 32, FIRST_PSEUDO_REGISTER,
        !          1957:                      frame_base_name, offset, n_fregs);
        !          1958:     }
        !          1959: 
        !          1960:   /* Work out how to skip the caller's unimp instruction if required.  */
        !          1961:   if (leaf_function)
        !          1962:     ret = (current_function_returns_struct ? "jmp %o7+12" : "retl");
        !          1963:   else
        !          1964:     ret = (current_function_returns_struct ? "jmp %i7+12" : "ret");
        !          1965: 
        !          1966:   /* Tail calls have to do this work themselves.  */
        !          1967:   if (leaf_function >= 0)
        !          1968:     {
        !          1969:       if (TARGET_EPILOGUE || leaf_label)
        !          1970:        {
        !          1971:          int old_target_epilogue = TARGET_EPILOGUE;
        !          1972:          target_flags &= ~old_target_epilogue;
        !          1973: 
        !          1974:          if (! leaf_function)
        !          1975:            {
        !          1976:              /* If we wound up with things in our delay slot,
        !          1977:                 flush them here.  */
        !          1978:              if (current_function_epilogue_delay_list)
        !          1979:                {
        !          1980:                  rtx insn = emit_jump_insn_after (gen_rtx (RETURN, VOIDmode),
        !          1981:                                                   get_last_insn ());
        !          1982:                  PATTERN (insn) = gen_rtx (PARALLEL, VOIDmode,
        !          1983:                                            gen_rtvec (2,
        !          1984:                                                       PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
        !          1985:                                                       PATTERN (insn)));
        !          1986:                  final_scan_insn (insn, file, 1, 0, 1);
        !          1987:                }
        !          1988:              else
        !          1989:                fprintf (file, "\t%s\n\trestore\n", ret);
        !          1990:            }
        !          1991:          else if (actual_fsize < 4096)
        !          1992:            {
        !          1993:              if (current_function_epilogue_delay_list)
        !          1994:                {
        !          1995:                  fprintf (file, "\t%s\n", ret);
        !          1996:                  final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
        !          1997:                                   file, 1, 0, 1);
        !          1998:                }
        !          1999:              else
        !          2000:                fprintf (file, "\t%s\n\tadd %%sp,%d,%%sp\n",
        !          2001:                         ret, actual_fsize);
        !          2002:            }
        !          2003:          else
        !          2004:            {
        !          2005:              if (current_function_epilogue_delay_list)
        !          2006:                abort ();
        !          2007:              fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
        !          2008:                       actual_fsize, actual_fsize, ret);
        !          2009:            }
        !          2010:          target_flags |= old_target_epilogue;
        !          2011:        }
        !          2012:     }
        !          2013:   else if (true_epilogue)
        !          2014:     {
        !          2015:       /* We may still need a return insn!  Somebody could jump around
        !          2016:         the tail-calls that this function makes.  */
        !          2017:       if (TARGET_EPILOGUE)
        !          2018:        {
        !          2019:          rtx last = get_last_insn ();
        !          2020: 
        !          2021:          last = prev_nonnote_insn (last);
        !          2022:          if (last == 0
        !          2023:              || (GET_CODE (last) != JUMP_INSN && GET_CODE (last) != BARRIER))
        !          2024:            fprintf (file, "\t%s\n\tnop\n", ret);
        !          2025:        }
        !          2026:     }
        !          2027: }
        !          2028: 
        !          2029: /* Return the string to output a conditional branch to LABEL, which is
        !          2030:    the operand number of the label.  OP is the conditional expression.  The
        !          2031:    mode of register 0 says what kind of comparison we made.
        !          2032: 
        !          2033:    REVERSED is non-zero if we should reverse the sense of the comparison.
        !          2034: 
        !          2035:    ANNUL is non-zero if we should generate an annulling branch.
        !          2036: 
        !          2037:    NOOP is non-zero if we have to follow this branch by a noop.  */
        !          2038: 
        !          2039: char *
        !          2040: output_cbranch (op, label, reversed, annul, noop)
        !          2041:      rtx op;
        !          2042:      int label;
        !          2043:      int reversed, annul, noop;
        !          2044: {
        !          2045:   static char string[20];
        !          2046:   enum rtx_code code = GET_CODE (op);
        !          2047:   enum machine_mode mode = GET_MODE (XEXP (op, 0));
        !          2048:   static char labelno[] = " %lX";
        !          2049: 
        !          2050:   /* ??? FP branches can not be preceeded by another floating point insn.
        !          2051:      Because there is currently no concept of pre-delay slots, we can fix
        !          2052:      this only by always emitting a nop before a floating point branch.  */
        !          2053: 
        !          2054:   if (mode == CCFPmode)
        !          2055:     strcpy (string, "nop\n\t");
        !          2056: 
        !          2057:   /* If not floating-point or if EQ or NE, we can just reverse the code.  */
        !          2058:   if (reversed && (mode != CCFPmode || code == EQ || code == NE))
        !          2059:     code = reverse_condition (code), reversed = 0;
        !          2060: 
        !          2061:   /* Start by writing the branch condition.  */
        !          2062:   switch (code)
        !          2063:     {
        !          2064:     case NE:
        !          2065:       if (mode == CCFPmode)
        !          2066:        strcat (string, "fbne");
        !          2067:       else
        !          2068:        strcpy (string, "bne");
        !          2069:       break;
        !          2070: 
        !          2071:     case EQ:
        !          2072:       if (mode == CCFPmode)
        !          2073:        strcat (string, "fbe");
        !          2074:       else
        !          2075:        strcpy (string, "be");
        !          2076:       break;
        !          2077: 
        !          2078:     case GE:
        !          2079:       if (mode == CCFPmode)
        !          2080:        {
        !          2081:          if (reversed)
        !          2082:            strcat (string, "fbul");
        !          2083:          else
        !          2084:            strcat (string, "fbge");
        !          2085:        }
        !          2086:       else if (mode == CC_NOOVmode)
        !          2087:        strcpy (string, "bpos");
        !          2088:       else
        !          2089:        strcpy (string, "bge");
        !          2090:       break;
        !          2091: 
        !          2092:     case GT:
        !          2093:       if (mode == CCFPmode)
        !          2094:        {
        !          2095:          if (reversed)
        !          2096:            strcat (string, "fbule");
        !          2097:          else
        !          2098:            strcat (string, "fbg");
        !          2099:        }
        !          2100:       else
        !          2101:        strcpy (string, "bg");
        !          2102:       break;
        !          2103: 
        !          2104:     case LE:
        !          2105:       if (mode == CCFPmode)
        !          2106:        {
        !          2107:          if (reversed)
        !          2108:            strcat (string, "fbug");
        !          2109:          else
        !          2110:            strcat (string, "fble");
        !          2111:        }
        !          2112:       else
        !          2113:        strcpy (string, "ble");
        !          2114:       break;
        !          2115: 
        !          2116:     case LT:
        !          2117:       if (mode == CCFPmode)
        !          2118:        {
        !          2119:          if (reversed)
        !          2120:            strcat (string, "fbuge");
        !          2121:          else
        !          2122:            strcat (string, "fbl");
        !          2123:        }
        !          2124:       else if (mode == CC_NOOVmode)
        !          2125:        strcpy (string, "bneg");
        !          2126:       else
        !          2127:        strcpy (string, "bl");
        !          2128:       break;
        !          2129: 
        !          2130:     case GEU:
        !          2131:       strcpy (string, "bgeu");
        !          2132:       break;
        !          2133: 
        !          2134:     case GTU:
        !          2135:       strcpy (string, "bgu");
        !          2136:       break;
        !          2137: 
        !          2138:     case LEU:
        !          2139:       strcpy (string, "bleu");
        !          2140:       break;
        !          2141: 
        !          2142:     case LTU:
        !          2143:       strcpy (string, "blu");
        !          2144:       break;
        !          2145:     }
        !          2146: 
        !          2147:   /* Now add the annulling, the label, and a possible noop.  */
        !          2148:   if (annul)
        !          2149:     strcat (string, ",a");
        !          2150: 
        !          2151:   labelno[3] = label + '0';
        !          2152:   strcat (string, labelno);
        !          2153: 
        !          2154:   if (noop)
        !          2155:     strcat (string, "\n\tnop");
        !          2156: 
        !          2157:   return string;
        !          2158: }
        !          2159: 
        !          2160: char *
        !          2161: output_return (operands)
        !          2162:      rtx *operands;
        !          2163: {
        !          2164:   if (leaf_label)
        !          2165:     {
        !          2166:       operands[0] = leaf_label;
        !          2167:       return "b,a %l0";
        !          2168:     }
        !          2169:   else if (leaf_function)
        !          2170:     {
        !          2171:       operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize);
        !          2172:       if (actual_fsize < 4096)
        !          2173:        {
        !          2174:          if (current_function_returns_struct)
        !          2175:            return "jmp %%o7+12\n\tadd %%sp,%0,%%sp";
        !          2176:          else
        !          2177:            return "retl\n\tadd %%sp,%0,%%sp";
        !          2178:        }
        !          2179:       else
        !          2180:        {
        !          2181:          if (current_function_returns_struct)
        !          2182:            return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
        !          2183:          else
        !          2184:            return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
        !          2185:        }
        !          2186:     }
        !          2187:   else
        !          2188:     {
        !          2189:       if (current_function_returns_struct)
        !          2190:        return "jmp %%i7+12\n\trestore";
        !          2191:       else
        !          2192:        return "ret\n\trestore";
        !          2193:     }
        !          2194: }
        !          2195: 
        !          2196: char *
        !          2197: output_floatsisf2 (operands)
        !          2198:      rtx *operands;
        !          2199: {
        !          2200:   if (GET_CODE (operands[1]) == MEM)
        !          2201:     return "ld %1,%0\n\tfitos %0,%0";
        !          2202:   else if (FP_REG_P (operands[1]))
        !          2203:     return "fitos %1,%0";
        !          2204:   return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitos %0,%0";
        !          2205: }
        !          2206: 
        !          2207: char *
        !          2208: output_floatsidf2 (operands)
        !          2209:      rtx *operands;
        !          2210: {
        !          2211:   if (GET_CODE (operands[1]) == MEM)
        !          2212:     return "ld %1,%0\n\tfitod %0,%0";
        !          2213:   else if (FP_REG_P (operands[1]))
        !          2214:     return "fitod %1,%0";
        !          2215:   return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitod %0,%0";
        !          2216: }
        !          2217: 
        !          2218: int
        !          2219: tail_call_valid_p ()
        !          2220: {
        !          2221:   static int checked = 0;
        !          2222:   static int valid_p = 0;
        !          2223: 
        !          2224:   if (! checked)
        !          2225:     {
        !          2226:       register int i;
        !          2227: 
        !          2228:       checked = 1;
        !          2229:       for (i = 32; i < FIRST_PSEUDO_REGISTER; i++)
        !          2230:        if (! fixed_regs[i] && ! call_used_regs[i])
        !          2231:          return 0;
        !          2232:       valid_p = 1;
        !          2233:     }
        !          2234:   return valid_p;
        !          2235: }
        !          2236: 
        !          2237: /* Leaf functions and non-leaf functions have different needs.  */
        !          2238: 
        !          2239: static int
        !          2240: reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER;
        !          2241: 
        !          2242: static int
        !          2243: reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER;
        !          2244: 
        !          2245: static int *reg_alloc_orders[] = {
        !          2246:   reg_leaf_alloc_order,
        !          2247:   reg_nonleaf_alloc_order};
        !          2248: 
        !          2249: void
        !          2250: order_regs_for_local_alloc ()
        !          2251: {
        !          2252:   static int last_order_nonleaf = 1;
        !          2253: 
        !          2254:   if (regs_ever_live[15] != last_order_nonleaf)
        !          2255:     {
        !          2256:       last_order_nonleaf = !last_order_nonleaf;
        !          2257:       bcopy (reg_alloc_orders[last_order_nonleaf], reg_alloc_order,
        !          2258:             FIRST_PSEUDO_REGISTER * sizeof (int));
        !          2259:     }
        !          2260: }
        !          2261: 
        !          2262: /* Machine dependent routines for the branch probability, arc profiling
        !          2263:    code.  */
        !          2264: 
        !          2265: /* The label used by the arc profiling code.  */
        !          2266: 
        !          2267: static rtx profiler_label;
        !          2268: 
        !          2269: void
        !          2270: init_arc_profiler ()
        !          2271: {
        !          2272:   /* Generate and save a copy of this so it can be shared.  */
        !          2273:   profiler_label = gen_rtx (SYMBOL_REF, Pmode, "*LPBX2");
        !          2274: }
        !          2275: 
        !          2276: void
        !          2277: output_arc_profiler (arcno, insert_after)
        !          2278:      int arcno;
        !          2279:      rtx insert_after;
        !          2280: {
        !          2281:   rtx profiler_target_addr
        !          2282:     = gen_rtx (CONST, Pmode,
        !          2283:               gen_rtx (PLUS, Pmode, profiler_label,
        !          2284:                        gen_rtx (CONST_INT, VOIDmode, 4 * arcno)));
        !          2285:   register rtx profiler_reg = gen_reg_rtx (SImode);
        !          2286:   register rtx temp = gen_reg_rtx (Pmode);
        !          2287:   register rtx profiler_target = gen_rtx (MEM, SImode,
        !          2288:                                          gen_rtx (LO_SUM, Pmode, temp,
        !          2289:                                                   profiler_target_addr));
        !          2290:   /* The insns are emitted from last to first after the insn insert_after.
        !          2291:      Emit_insn_after is used because sometimes we want to put the
        !          2292:      instrumentation code after the last insn of the function.  */
        !          2293:   emit_insn_after (gen_rtx (SET, VOIDmode, profiler_target, profiler_reg),
        !          2294:                   insert_after);
        !          2295:   emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg,
        !          2296:                            gen_rtx (PLUS, SImode, profiler_reg, const1_rtx)),
        !          2297:                   insert_after);
        !          2298:   emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg, profiler_target),
        !          2299:                   insert_after);
        !          2300:   emit_insn_after (gen_rtx (SET, VOIDmode, temp,
        !          2301:                            gen_rtx (HIGH, Pmode, profiler_target_addr)),
        !          2302:                   insert_after);
        !          2303: }
        !          2304: 
        !          2305: /* All the remaining routines in this file have been turned off.  */
        !          2306: #if 0
        !          2307: char *
        !          2308: output_tail_call (operands, insn)
        !          2309:      rtx *operands;
        !          2310:      rtx insn;
        !          2311: {
        !          2312:   int this_fsize = actual_fsize;
        !          2313:   rtx next;
        !          2314:   int need_nop_at_end = 0;
        !          2315: 
        !          2316:   next = next_real_insn (insn);
        !          2317:   while (next && GET_CODE (next) == CODE_LABEL)
        !          2318:     next = next_real_insn (insn);
        !          2319: 
        !          2320:   if (final_sequence && this_fsize > 0)
        !          2321:     {
        !          2322:       rtx xoperands[1];
        !          2323: 
        !          2324:       /* If we have to restore any registers, don't take any chances
        !          2325:         restoring a register before we discharge it into
        !          2326:         its home.  If the frame size is only 88, we are guaranteed
        !          2327:         that the epilogue will fit in the delay slot.  */
        !          2328:       rtx delay_insn = XVECEXP (final_sequence, 0, 1);
        !          2329:       if (GET_CODE (PATTERN (delay_insn)) == SET)
        !          2330:        {
        !          2331:          rtx dest = SET_DEST (PATTERN (delay_insn));
        !          2332:          if (GET_CODE (dest) == REG
        !          2333:              && reg_mentioned_p (dest, insn))
        !          2334:            abort ();
        !          2335:        }
        !          2336:       else if (GET_CODE (PATTERN (delay_insn)) == PARALLEL)
        !          2337:        abort ();
        !          2338:       xoperands[0] = operands[0];
        !          2339:       final_scan_insn (delay_insn, asm_out_file, 0, 0, 1);
        !          2340:       operands[0] = xoperands[0];
        !          2341:       final_sequence = 0;
        !          2342:     }
        !          2343: 
        !          2344:   /* Make sure we are clear to return.  */
        !          2345:   output_function_epilogue (asm_out_file, get_frame_size (), -1, 0);
        !          2346: 
        !          2347:   /* Strip the MEM.  */
        !          2348:   operands[0] = XEXP (operands[0], 0);
        !          2349: 
        !          2350:   if (final_sequence == 0
        !          2351:       && (next == 0
        !          2352:          || GET_CODE (next) == CALL_INSN
        !          2353:          || GET_CODE (next) == JUMP_INSN))
        !          2354:     need_nop_at_end = 1;
        !          2355: 
        !          2356:   if (flag_pic)
        !          2357:     return output_pic_sequence_2 (2, 3, 0, "jmpl %%g1+%3", operands, need_nop_at_end);
        !          2358: 
        !          2359:   if (GET_CODE (operands[0]) == REG)
        !          2360:     output_asm_insn ("jmpl %a0,%%g0", operands);
        !          2361:   else if (TARGET_TAIL_CALL)
        !          2362:     {
        !          2363:       /* We assume all labels will be within 16 MB of our call.  */
        !          2364:       if (need_nop_at_end || final_sequence)
        !          2365:        output_asm_insn ("b %a0", operands);
        !          2366:       else
        !          2367:        output_asm_insn ("b,a %a0", operands);
        !          2368:     }
        !          2369:   else if (! final_sequence)
        !          2370:     {
        !          2371:       output_asm_insn ("sethi %%hi(%a0),%%g1\n\tjmpl %%g1+%%lo(%a0),%%g1",
        !          2372:                       operands);
        !          2373:     }
        !          2374:   else
        !          2375:     {
        !          2376:       int i;
        !          2377:       rtx x = PATTERN (XVECEXP (final_sequence, 0, 1));
        !          2378:       for (i = 1; i < 32; i++)
        !          2379:        if ((i == 1 || ! fixed_regs[i])
        !          2380:            && call_used_regs[i]
        !          2381:            && ! refers_to_regno_p (i, i+1, x, 0))
        !          2382:          break;
        !          2383:       if (i == 32)
        !          2384:        abort ();
        !          2385:       operands[1] = gen_rtx (REG, SImode, i);
        !          2386:       output_asm_insn ("sethi %%hi(%a0),%1\n\tjmpl %1+%%lo(%a0),%1", operands);
        !          2387:     }
        !          2388:   return (need_nop_at_end ? "nop" : "");
        !          2389: }
        !          2390: #endif
        !          2391: 
        !          2392: /* Print operand X (an rtx) in assembler syntax to file FILE.
        !          2393:    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
        !          2394:    For `%' followed by punctuation, CODE is the punctuation and X is null.  */
        !          2395: 
        !          2396: void
        !          2397: print_operand (file, x, code)
        !          2398:      FILE *file;
        !          2399:      rtx x;
        !          2400:      int code;
        !          2401: {
        !          2402:   switch (code)
        !          2403:     {
        !          2404:     case '#':
        !          2405:       /* Output a 'nop' if there's nothing for the delay slot.  */
        !          2406:       if (dbr_sequence_length () == 0)
        !          2407:        fputs ("\n\tnop", file);
        !          2408:       return;
        !          2409:     case '*':
        !          2410:       /* Output an annul flag if there's nothing for the delay slot.  */
        !          2411:       if (dbr_sequence_length () == 0)
        !          2412:         fputs (",a", file);
        !          2413:       return;
        !          2414:     case 'Y':
        !          2415:       /* Adjust the operand to take into account a RESTORE operation.  */
        !          2416:       if (GET_CODE (x) != REG)
        !          2417:        abort ();
        !          2418:       if (REGNO (x) < 8)
        !          2419:        fputs (reg_names[REGNO (x)], file);
        !          2420:       else if (REGNO (x) >= 24 && REGNO (x) < 32)
        !          2421:        fputs (reg_names[REGNO (x)-16], file);
        !          2422:       else
        !          2423:        abort ();
        !          2424:       return;
        !          2425:     case '@':
        !          2426:       /* Print out what we are using as the frame pointer.  This might
        !          2427:         be %fp, or might be %sp+offset.  */
        !          2428:       fputs (frame_base_name, file);
        !          2429:       return;
        !          2430:     case 'R':
        !          2431:       /* Print out the second register name of a register pair.
        !          2432:         I.e., R (%o0) => %o1.  */
        !          2433:       fputs (reg_names[REGNO (x)+1], file);
        !          2434:       return;
        !          2435:     case 'm':
        !          2436:       /* Print the operand's address only.  */
        !          2437:       output_address (XEXP (x, 0));
        !          2438:       return;
        !          2439:     case 'r':
        !          2440:       /* In this case we need a register.  Use %g0 if the
        !          2441:         operand in const0_rtx.  */
        !          2442:       if (x == const0_rtx)
        !          2443:        {
        !          2444:          fputs ("%g0", file);
        !          2445:          return;
        !          2446:        }
        !          2447:       else
        !          2448:        break;
        !          2449: 
        !          2450:     case  'A':
        !          2451:       switch (GET_CODE (x))
        !          2452:        {
        !          2453:        case IOR: fputs ("or", file); break;
        !          2454:        case AND: fputs ("and", file); break;
        !          2455:        case XOR: fputs ("xor", file); break;
        !          2456:        default: abort ();
        !          2457:        }
        !          2458:       return;
        !          2459: 
        !          2460:     case 'B':
        !          2461:       switch (GET_CODE (x))
        !          2462:        {
        !          2463:        case IOR: fputs ("orn", file); break;
        !          2464:        case AND: fputs ("andn", file); break;
        !          2465:        case XOR: fputs ("xnor", file); break;
        !          2466:        default: abort ();
        !          2467:        }
        !          2468:       return;
        !          2469: 
        !          2470:     case 'b':
        !          2471:       {
        !          2472:        /* Print a sign-extended character.  */
        !          2473:        int i = INTVAL (x) & 0xff;
        !          2474:        if (i & 0x80)
        !          2475:          i |= 0xffffff00;
        !          2476:        fprintf (file, "%d", i);
        !          2477:        return;
        !          2478:       }
        !          2479: 
        !          2480:     case 0:
        !          2481:       /* Do nothing special.  */
        !          2482:       break;
        !          2483: 
        !          2484:     default:
        !          2485:       /* Undocumented flag.  */
        !          2486:       abort ();
        !          2487:     }
        !          2488: 
        !          2489:   if (GET_CODE (x) == REG)
        !          2490:     fputs (reg_names[REGNO (x)], file);
        !          2491:   else if (GET_CODE (x) == MEM)
        !          2492:     {
        !          2493:       fputc ('[', file);
        !          2494:       if (CONSTANT_P (XEXP (x, 0)))
        !          2495:        /* Poor Sun assembler doesn't understand absolute addressing.  */
        !          2496:        fputs ("%g0+", file);
        !          2497:       output_address (XEXP (x, 0));
        !          2498:       fputc (']', file);
        !          2499:     }
        !          2500:   else if (GET_CODE (x) == HIGH)
        !          2501:     {
        !          2502:       fputs ("%hi(", file);
        !          2503:       output_addr_const (file, XEXP (x, 0));
        !          2504:       fputc (')', file);
        !          2505:     }
        !          2506:   else if (GET_CODE (x) == LO_SUM)
        !          2507:     {
        !          2508:       print_operand (file, XEXP (x, 0), 0);
        !          2509:       fputs ("+%lo(", file);
        !          2510:       output_addr_const (file, XEXP (x, 1));
        !          2511:       fputc (')', file);
        !          2512:     }
        !          2513:   else if (GET_CODE (x) == CONST_DOUBLE)
        !          2514:     {
        !          2515:       if (CONST_DOUBLE_HIGH (x) == 0)
        !          2516:        fprintf (file, "%u", CONST_DOUBLE_LOW (x));
        !          2517:       else if (CONST_DOUBLE_HIGH (x) == -1
        !          2518:               && CONST_DOUBLE_LOW (x) < 0)
        !          2519:        fprintf (file, "%d", CONST_DOUBLE_LOW (x));
        !          2520:       else
        !          2521:        abort ();
        !          2522:     }
        !          2523:   else { output_addr_const (file, x); }
        !          2524: }
        !          2525: 
        !          2526: /* This function outputs assembler code for VALUE to FILE, where VALUE is
        !          2527:    a 64 bit (DImode) value.  */
        !          2528: 
        !          2529: /* ??? If there is a 64 bit counterpart to .word that the assembler
        !          2530:    understands, then using that would simply this code greatly.  */
        !          2531: 
        !          2532: void
        !          2533: output_double_int (file, value)
        !          2534:      FILE *file;
        !          2535:      rtx value;
        !          2536: {
        !          2537:   if (GET_CODE (value) == CONST_INT)
        !          2538:     {
        !          2539:       if (INTVAL (value) < 0)
        !          2540:        ASM_OUTPUT_INT (file, constm1_rtx);
        !          2541:       else
        !          2542:        ASM_OUTPUT_INT (file, const0_rtx);
        !          2543:       ASM_OUTPUT_INT (file, value);
        !          2544:     }
        !          2545:   else if (GET_CODE (value) == CONST_DOUBLE)
        !          2546:     {
        !          2547:       ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode,
        !          2548:                                     CONST_DOUBLE_HIGH (value)));
        !          2549:       ASM_OUTPUT_INT (file, gen_rtx (CONST_INT, VOIDmode,
        !          2550:                                     CONST_DOUBLE_LOW (value)));
        !          2551:     }
        !          2552:   else if (GET_CODE (value) == SYMBOL_REF
        !          2553:           || GET_CODE (value) == CONST
        !          2554:           || GET_CODE (value) == PLUS)
        !          2555:     {
        !          2556:       /* Addresses are only 32 bits.  */
        !          2557:       ASM_OUTPUT_INT (file, const0_rtx);
        !          2558:       ASM_OUTPUT_INT (file, value);
        !          2559:     }
        !          2560:   else
        !          2561:     abort ();
        !          2562: }
        !          2563: 

unix.superglobalmegacorp.com

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