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

1.1     ! root        1: /* Subroutines for insn-output.c for Intel 860
        !             2:    Copyright (C) 1989, 1991 Free Software Foundation, Inc.
        !             3:    Derived from sparc.c.
        !             4: 
        !             5:    Written by Richard Stallman ([email protected]).
        !             6: 
        !             7:    Hacked substantially by Ron Guilmette ([email protected]) to cater
        !             8:    to the whims of the System V Release 4 assembler.
        !             9: 
        !            10: This file is part of GNU CC.
        !            11: 
        !            12: GNU CC is free software; you can redistribute it and/or modify
        !            13: it under the terms of the GNU General Public License as published by
        !            14: the Free Software Foundation; either version 2, or (at your option)
        !            15: any later version.
        !            16: 
        !            17: GNU CC is distributed in the hope that it will be useful,
        !            18: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            19: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            20: GNU General Public License for more details.
        !            21: 
        !            22: You should have received a copy of the GNU General Public License
        !            23: along with GNU CC; see the file COPYING.  If not, write to
        !            24: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            25: 
        !            26: 
        !            27: #include "config.h"
        !            28: #include "flags.h"
        !            29: #include "rtl.h"
        !            30: #include "regs.h"
        !            31: #include "hard-reg-set.h"
        !            32: #include "real.h"
        !            33: #include "insn-config.h"
        !            34: #include "conditions.h"
        !            35: #include "insn-flags.h"
        !            36: #include "output.h"
        !            37: #include "recog.h"
        !            38: #include "insn-attr.h"
        !            39: 
        !            40: #include <stdio.h>
        !            41: 
        !            42: static rtx find_addr_reg ();
        !            43: 
        !            44: #ifndef I860_REG_PREFIX
        !            45: #define I860_REG_PREFIX ""
        !            46: #endif
        !            47: 
        !            48: char *i860_reg_prefix = I860_REG_PREFIX;
        !            49: 
        !            50: /* Save information from a "cmpxx" operation until the branch is emitted.  */
        !            51: 
        !            52: rtx i860_compare_op0, i860_compare_op1;
        !            53: 
        !            54: /* Return non-zero if this pattern, can be evaluated safely, even if it
        !            55:    was not asked for.  */
        !            56: int
        !            57: safe_insn_src_p (op, mode)
        !            58:      rtx op;
        !            59:      enum machine_mode mode;
        !            60: {
        !            61:   /* Just experimenting.  */
        !            62: 
        !            63:   /* No floating point src is safe if it contains an arithmetic
        !            64:      operation, since that operation may trap.  */
        !            65:   switch (GET_CODE (op))
        !            66:     {
        !            67:     case CONST_INT:
        !            68:     case LABEL_REF:
        !            69:     case SYMBOL_REF:
        !            70:     case CONST:
        !            71:       return 1;
        !            72: 
        !            73:     case REG:
        !            74:       return 1;
        !            75: 
        !            76:     case MEM:
        !            77:       return CONSTANT_ADDRESS_P (XEXP (op, 0));
        !            78: 
        !            79:       /* We never need to negate or complement constants.  */
        !            80:     case NEG:
        !            81:       return (mode != SFmode && mode != DFmode);
        !            82:     case NOT:
        !            83:     case ZERO_EXTEND:
        !            84:       return 1;
        !            85: 
        !            86:     case EQ:
        !            87:     case NE:
        !            88:     case LT:
        !            89:     case GT:
        !            90:     case LE:
        !            91:     case GE:
        !            92:     case LTU:
        !            93:     case GTU:
        !            94:     case LEU:
        !            95:     case GEU:
        !            96:     case MINUS:
        !            97:     case PLUS:
        !            98:       return (mode != SFmode && mode != DFmode);
        !            99:     case AND:
        !           100:     case IOR:
        !           101:     case XOR:
        !           102:     case LSHIFT:
        !           103:     case ASHIFT:
        !           104:     case ASHIFTRT:
        !           105:     case LSHIFTRT:
        !           106:       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
        !           107:          || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
        !           108:        return 0;
        !           109:       return 1;
        !           110: 
        !           111:     default:
        !           112:       return 0;
        !           113:     }
        !           114: }
        !           115: 
        !           116: /* Return 1 if REG is clobbered in IN.
        !           117:    Return 2 if REG is used in IN. 
        !           118:    Return 3 if REG is both used and clobbered in IN.
        !           119:    Return 0 if neither.  */
        !           120: 
        !           121: static int
        !           122: reg_clobbered_p (reg, in)
        !           123:      rtx reg;
        !           124:      rtx in;
        !           125: {
        !           126:   register enum rtx_code code;
        !           127: 
        !           128:   if (in == 0)
        !           129:     return 0;
        !           130: 
        !           131:   code = GET_CODE (in);
        !           132: 
        !           133:   if (code == SET || code == CLOBBER)
        !           134:     {
        !           135:       rtx dest = SET_DEST (in);
        !           136:       int set = 0;
        !           137:       int used = 0;
        !           138: 
        !           139:       while (GET_CODE (dest) == STRICT_LOW_PART
        !           140:             || GET_CODE (dest) == SUBREG
        !           141:             || GET_CODE (dest) == SIGN_EXTRACT
        !           142:             || GET_CODE (dest) == ZERO_EXTRACT)
        !           143:        dest = XEXP (dest, 0);
        !           144: 
        !           145:       if (dest == reg)
        !           146:        set = 1;
        !           147:       else if (GET_CODE (dest) == REG
        !           148:               && refers_to_regno_p (REGNO (reg),
        !           149:                                     REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           150:                                     SET_DEST (in), 0))
        !           151:        {
        !           152:          set = 1;
        !           153:          /* Anything that sets just part of the register
        !           154:             is considered using as well as setting it.
        !           155:             But note that a straight SUBREG of a single-word value
        !           156:             clobbers the entire value.   */
        !           157:          if (dest != SET_DEST (in)
        !           158:              && ! (GET_CODE (SET_DEST (in)) == SUBREG
        !           159:                    || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))
        !           160:            used = 1;
        !           161:        }
        !           162: 
        !           163:       if (code == SET)
        !           164:        {
        !           165:          if (set)
        !           166:            used = refers_to_regno_p (REGNO (reg),
        !           167:                                      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           168:                                      SET_SRC (in), 0);
        !           169:          else
        !           170:            used = refers_to_regno_p (REGNO (reg),
        !           171:                                      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           172:                                      in, 0);
        !           173:        }
        !           174: 
        !           175:       return set + used * 2;
        !           176:     }
        !           177: 
        !           178:   if (refers_to_regno_p (REGNO (reg),
        !           179:                         REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
        !           180:                         in, 0))
        !           181:     return 2;
        !           182:   return 0;
        !           183: }
        !           184: 
        !           185: /* Return non-zero if OP can be written to without screwing up
        !           186:    GCC's model of what's going on.  It is assumed that this operand
        !           187:    appears in the dest position of a SET insn in a conditional
        !           188:    branch's delay slot.  AFTER is the label to start looking from.  */
        !           189: int
        !           190: operand_clobbered_before_used_after (op, after)
        !           191:      rtx op;
        !           192:      rtx after;
        !           193: {
        !           194:   /* Just experimenting.  */
        !           195:   if (GET_CODE (op) == CC0)
        !           196:     return 1;
        !           197:   if (GET_CODE (op) == REG)
        !           198:     {
        !           199:       rtx insn;
        !           200: 
        !           201:       if (op == stack_pointer_rtx)
        !           202:        return 0;
        !           203: 
        !           204:       /* Scan forward from the label, to see if the value of OP
        !           205:         is clobbered before the first use.  */
        !           206: 
        !           207:       for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
        !           208:        {
        !           209:          if (GET_CODE (insn) == NOTE)
        !           210:            continue;
        !           211:          if (GET_CODE (insn) == INSN
        !           212:              || GET_CODE (insn) == JUMP_INSN
        !           213:              || GET_CODE (insn) == CALL_INSN)
        !           214:            {
        !           215:              switch (reg_clobbered_p (op, PATTERN (insn)))
        !           216:                {
        !           217:                default:
        !           218:                  return 0;
        !           219:                case 1:
        !           220:                  return 1;
        !           221:                case 0:
        !           222:                  break;
        !           223:                }
        !           224:            }
        !           225:          /* If we reach another label without clobbering OP,
        !           226:             then we cannot safely write it here.  */
        !           227:          else if (GET_CODE (insn) == CODE_LABEL)
        !           228:            return 0;
        !           229:          if (GET_CODE (insn) == JUMP_INSN)
        !           230:            {
        !           231:              if (condjump_p (insn))
        !           232:                return 0;
        !           233:              /* This is a jump insn which has already
        !           234:                 been mangled.  We can't tell what it does.  */
        !           235:              if (GET_CODE (PATTERN (insn)) == PARALLEL)
        !           236:                return 0;
        !           237:              if (! JUMP_LABEL (insn))
        !           238:                return 0;
        !           239:              /* Keep following jumps.  */
        !           240:              insn = JUMP_LABEL (insn);
        !           241:            }
        !           242:        }
        !           243:       return 1;
        !           244:     }
        !           245: 
        !           246:   /* In both of these cases, the first insn executed
        !           247:      for this op will be a orh whatever%h,%?r0,%?r31,
        !           248:      which is tolerable.  */
        !           249:   if (GET_CODE (op) == MEM)
        !           250:     return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
        !           251: 
        !           252:   return 0;
        !           253: }
        !           254: 
        !           255: /* Return non-zero if this pattern, as a source to a "SET",
        !           256:    is known to yield an instruction of unit size.  */
        !           257: int
        !           258: single_insn_src_p (op, mode)
        !           259:      rtx op;
        !           260:      enum machine_mode mode;
        !           261: {
        !           262:   switch (GET_CODE (op))
        !           263:     {
        !           264:     case CONST_INT:
        !           265:       /* This is not always a single insn src, technically,
        !           266:         but output_delayed_branch knows how to deal with it.  */
        !           267:       return 1;
        !           268: 
        !           269:     case SYMBOL_REF:
        !           270:     case CONST:
        !           271:       /* This is not a single insn src, technically,
        !           272:         but output_delayed_branch knows how to deal with it.  */
        !           273:       return 1;
        !           274: 
        !           275:     case REG:
        !           276:       return 1;
        !           277: 
        !           278:     case MEM:
        !           279:       return 1;
        !           280: 
        !           281:       /* We never need to negate or complement constants.  */
        !           282:     case NEG:
        !           283:       return (mode != DFmode);
        !           284:     case NOT:
        !           285:     case ZERO_EXTEND:
        !           286:       return 1;
        !           287: 
        !           288:     case PLUS:
        !           289:     case MINUS:
        !           290:       /* Detect cases that require multiple instructions.  */
        !           291:       if (CONSTANT_P (XEXP (op, 1))
        !           292:          && !(GET_CODE (XEXP (op, 1)) == CONST_INT
        !           293:               && SMALL_INT (XEXP (op, 1))))
        !           294:        return 0;
        !           295:     case EQ:
        !           296:     case NE:
        !           297:     case LT:
        !           298:     case GT:
        !           299:     case LE:
        !           300:     case GE:
        !           301:     case LTU:
        !           302:     case GTU:
        !           303:     case LEU:
        !           304:     case GEU:
        !           305:       /* Not doing floating point, since they probably
        !           306:         take longer than the branch slot they might fill.  */
        !           307:       return (mode != SFmode && mode != DFmode);
        !           308: 
        !           309:     case AND:
        !           310:       if (GET_CODE (XEXP (op, 1)) == NOT)
        !           311:        {
        !           312:          rtx arg = XEXP (XEXP (op, 1), 0);
        !           313:          if (CONSTANT_P (arg)
        !           314:              && !(GET_CODE (arg) == CONST_INT
        !           315:                   && (SMALL_INT (arg)
        !           316:                       || INTVAL (arg) & 0xffff == 0)))
        !           317:            return 0;
        !           318:        }
        !           319:     case IOR:
        !           320:     case XOR:
        !           321:       /* Both small and round numbers take one instruction;
        !           322:         others take two.  */
        !           323:       if (CONSTANT_P (XEXP (op, 1))
        !           324:          && !(GET_CODE (XEXP (op, 1)) == CONST_INT
        !           325:               && (SMALL_INT (XEXP (op, 1))
        !           326:                   || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
        !           327:        return 0;
        !           328: 
        !           329:     case LSHIFT:
        !           330:     case ASHIFT:
        !           331:     case ASHIFTRT:
        !           332:     case LSHIFTRT:
        !           333:       return 1;
        !           334: 
        !           335:     case SUBREG:
        !           336:       if (SUBREG_WORD (op) != 0)
        !           337:        return 0;
        !           338:       return single_insn_src_p (SUBREG_REG (op), mode);
        !           339: 
        !           340:       /* Not doing floating point, since they probably
        !           341:         take longer than the branch slot they might fill.  */
        !           342:     case FLOAT_EXTEND:
        !           343:     case FLOAT_TRUNCATE:
        !           344:     case FLOAT:
        !           345:     case FIX:
        !           346:     case UNSIGNED_FLOAT:
        !           347:     case UNSIGNED_FIX:
        !           348:       return 0;
        !           349: 
        !           350:     default:
        !           351:       return 0;
        !           352:     }
        !           353: }
        !           354: 
        !           355: /* Return non-zero only if OP is a register of mode MODE,
        !           356:    or const0_rtx.  */
        !           357: int
        !           358: reg_or_0_operand (op, mode)
        !           359:      rtx op;
        !           360:      enum machine_mode mode;
        !           361: {
        !           362:   return (op == const0_rtx || register_operand (op, mode)
        !           363:          || op == CONST0_RTX (mode));
        !           364: }
        !           365: 
        !           366: /* Return truth value of whether OP can be used as an operands in a three
        !           367:    address add/subtract insn (such as add %o1,7,%l2) of mode MODE.  */
        !           368: 
        !           369: int
        !           370: arith_operand (op, mode)
        !           371:      rtx op;
        !           372:      enum machine_mode mode;
        !           373: {
        !           374:   return (register_operand (op, mode)
        !           375:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
        !           376: }
        !           377: 
        !           378: /* Return 1 if OP is a valid first operand for a logical insn of mode MODE.  */
        !           379: 
        !           380: int
        !           381: logic_operand (op, mode)
        !           382:      rtx op;
        !           383:      enum machine_mode mode;
        !           384: {
        !           385:   return (register_operand (op, mode)
        !           386:          || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
        !           387: }
        !           388: 
        !           389: /* Return 1 if OP is a valid first operand for a shift insn of mode MODE.  */
        !           390: 
        !           391: int
        !           392: shift_operand (op, mode)
        !           393:      rtx op;
        !           394:      enum machine_mode mode;
        !           395: {
        !           396:   return (register_operand (op, mode)
        !           397:           || (GET_CODE (op) == CONST_INT));
        !           398: }
        !           399: 
        !           400: /* Return 1 if OP is a valid first operand for either a logical insn
        !           401:    or an add insn of mode MODE.  */
        !           402: 
        !           403: int
        !           404: compare_operand (op, mode)
        !           405:      rtx op;
        !           406:      enum machine_mode mode;
        !           407: {
        !           408:   return (register_operand (op, mode)
        !           409:          || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
        !           410: }
        !           411: 
        !           412: /* Return truth value of whether OP can be used as the 5-bit immediate
        !           413:    operand of a bte or btne insn.  */
        !           414: 
        !           415: int
        !           416: bte_operand (op, mode)
        !           417:      rtx op;
        !           418:      enum machine_mode mode;
        !           419: {
        !           420:   return (register_operand (op, mode)
        !           421:          || (GET_CODE (op) == CONST_INT
        !           422:              && (unsigned) INTVAL (op) < 0x20));
        !           423: }
        !           424: 
        !           425: /* Return 1 if OP is an indexed memory reference of mode MODE.  */
        !           426: 
        !           427: int
        !           428: indexed_operand (op, mode)
        !           429:      rtx op;
        !           430:      enum machine_mode mode;
        !           431: {
        !           432:   return (GET_CODE (op) == MEM && GET_MODE (op) == mode
        !           433:          && GET_CODE (XEXP (op, 0)) == PLUS
        !           434:          && GET_MODE (XEXP (op, 0)) == SImode
        !           435:          && register_operand (XEXP (XEXP (op, 0), 0), SImode)
        !           436:          && register_operand (XEXP (XEXP (op, 0), 1), SImode));
        !           437: }
        !           438: 
        !           439: /* Return 1 if OP is a suitable source operand for a load insn
        !           440:    with mode MODE.  */
        !           441: 
        !           442: int
        !           443: load_operand (op, mode)
        !           444:      rtx op;
        !           445:      enum machine_mode mode;
        !           446: {
        !           447:   return (memory_operand (op, mode) || indexed_operand (op, mode));
        !           448: }
        !           449: 
        !           450: /* Return truth value of whether OP is a integer which fits the
        !           451:    range constraining immediate operands in add/subtract insns.  */
        !           452: 
        !           453: int
        !           454: small_int (op, mode)
        !           455:      rtx op;
        !           456:      enum machine_mode mode;
        !           457: {
        !           458:   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
        !           459: }
        !           460: 
        !           461: /* Return truth value of whether OP is a integer which fits the
        !           462:    range constraining immediate operands in logic insns.  */
        !           463: 
        !           464: int
        !           465: logic_int (op, mode)
        !           466:      rtx op;
        !           467:      enum machine_mode mode;
        !           468: {
        !           469:   return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
        !           470: }
        !           471: 
        !           472: /* Test for a valid operand for a call instruction.
        !           473:    Don't allow the arg pointer register or virtual regs
        !           474:    since they may change into reg + const, which the patterns
        !           475:    can't handle yet.  */
        !           476: 
        !           477: int
        !           478: call_insn_operand (op, mode)
        !           479:      rtx op;
        !           480:      enum machine_mode mode;
        !           481: {
        !           482:   if (GET_CODE (op) == MEM
        !           483:       && (CONSTANT_ADDRESS_P (XEXP (op, 0))
        !           484:          || (GET_CODE (XEXP (op, 0)) == REG
        !           485:              && XEXP (op, 0) != arg_pointer_rtx
        !           486:              && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
        !           487:                   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
        !           488:     return 1;
        !           489:   return 0;
        !           490: }
        !           491: 
        !           492: /* Return the best assembler insn template
        !           493:    for moving operands[1] into operands[0] as a fullword.  */
        !           494: 
        !           495: static char *
        !           496: singlemove_string (operands)
        !           497:      rtx *operands;
        !           498: {
        !           499:   if (GET_CODE (operands[0]) == MEM)
        !           500:     {
        !           501:       if (GET_CODE (operands[1]) != MEM)
        !           502:        if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
        !           503:          {
        !           504:            if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !           505:                   && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !           506:                   && cc_prev_status.mdep == XEXP (operands[0], 0)))
        !           507:              {
        !           508:                CC_STATUS_INIT;
        !           509:                output_asm_insn ("orh %h0,%?r0,%?r31", operands);
        !           510:              }
        !           511:            cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
        !           512:            cc_status.mdep = XEXP (operands[0], 0);
        !           513:            return "st.l %r1,%L0(%?r31)";
        !           514:          }
        !           515:        else
        !           516:          return "st.l %r1,%0";
        !           517:       else
        !           518:        abort ();
        !           519: #if 0
        !           520:        {
        !           521:          rtx xoperands[2];
        !           522: 
        !           523:          cc_status.flags &= ~CC_F0_IS_0;
        !           524:          xoperands[0] = gen_rtx (REG, SFmode, 32);
        !           525:          xoperands[1] = operands[1];
        !           526:          output_asm_insn (singlemove_string (xoperands), xoperands);
        !           527:          xoperands[1] = xoperands[0];
        !           528:          xoperands[0] = operands[0];
        !           529:          output_asm_insn (singlemove_string (xoperands), xoperands);
        !           530:          return "";
        !           531:        }
        !           532: #endif
        !           533:     }
        !           534:   if (GET_CODE (operands[1]) == MEM)
        !           535:     {
        !           536:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
        !           537:        {
        !           538:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !           539:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !           540:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
        !           541:            {
        !           542:              CC_STATUS_INIT;
        !           543:              output_asm_insn ("orh %h1,%?r0,%?r31", operands);
        !           544:            }
        !           545:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
        !           546:          cc_status.mdep = XEXP (operands[1], 0);
        !           547:          return "ld.l %L1(%?r31),%0";
        !           548:        }
        !           549:       return "ld.l %m1,%0";
        !           550:     }
        !           551:  if (GET_CODE (operands[1]) == CONST_INT)
        !           552:    {
        !           553:      if (operands[1] == const0_rtx)
        !           554:       return "mov %?r0,%0";
        !           555:      if((INTVAL (operands[1]) & 0xffff0000) == 0)
        !           556:       return "or %L1,%?r0,%0";
        !           557:      if((INTVAL (operands[1]) & 0xffff8000) == 0xffff8000)
        !           558:       return "adds %1,%?r0,%0";
        !           559:      if((INTVAL (operands[1]) & 0x0000ffff) == 0)
        !           560:       return "orh %H1,%?r0,%0";
        !           561:    }
        !           562:   return "mov %1,%0";
        !           563: }
        !           564: 
        !           565: /* Output assembler code to perform a doubleword move insn
        !           566:    with operands OPERANDS.  */
        !           567: 
        !           568: char *
        !           569: output_move_double (operands)
        !           570:      rtx *operands;
        !           571: {
        !           572:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
        !           573:   rtx latehalf[2];
        !           574:   rtx addreg0 = 0, addreg1 = 0;
        !           575:   int highest_first = 0;
        !           576:   int no_addreg1_decrement = 0;
        !           577: 
        !           578:   /* First classify both operands.  */
        !           579: 
        !           580:   if (REG_P (operands[0]))
        !           581:     optype0 = REGOP;
        !           582:   else if (offsettable_memref_p (operands[0]))
        !           583:     optype0 = OFFSOP;
        !           584:   else if (GET_CODE (operands[0]) == MEM)
        !           585:     optype0 = MEMOP;
        !           586:   else
        !           587:     optype0 = RNDOP;
        !           588: 
        !           589:   if (REG_P (operands[1]))
        !           590:     optype1 = REGOP;
        !           591:   else if (CONSTANT_P (operands[1]))
        !           592:     optype1 = CNSTOP;
        !           593:   else if (offsettable_memref_p (operands[1]))
        !           594:     optype1 = OFFSOP;
        !           595:   else if (GET_CODE (operands[1]) == MEM)
        !           596:     optype1 = MEMOP;
        !           597:   else
        !           598:     optype1 = RNDOP;
        !           599: 
        !           600:   /* Check for the cases that the operand constraints are not
        !           601:      supposed to allow to happen.  Abort if we get one,
        !           602:      because generating code for these cases is painful.  */
        !           603: 
        !           604:   if (optype0 == RNDOP || optype1 == RNDOP)
        !           605:     abort ();
        !           606: 
        !           607:   /* If an operand is an unoffsettable memory ref, find a register
        !           608:      we can increment temporarily to make it refer to the second word.  */
        !           609: 
        !           610:   if (optype0 == MEMOP)
        !           611:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
        !           612: 
        !           613:   if (optype1 == MEMOP)
        !           614:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
        !           615: 
        !           616: /* ??? Perhaps in some cases move double words
        !           617:    if there is a spare pair of floating regs.  */
        !           618: 
        !           619:   /* Ok, we can do one word at a time.
        !           620:      Normally we do the low-numbered word first,
        !           621:      but if either operand is autodecrementing then we
        !           622:      do the high-numbered word first.
        !           623: 
        !           624:      In either case, set up in LATEHALF the operands to use
        !           625:      for the high-numbered word and in some cases alter the
        !           626:      operands in OPERANDS to be suitable for the low-numbered word.  */
        !           627: 
        !           628:   if (optype0 == REGOP)
        !           629:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
        !           630:   else if (optype0 == OFFSOP)
        !           631:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
        !           632:   else
        !           633:     latehalf[0] = operands[0];
        !           634: 
        !           635:   if (optype1 == REGOP)
        !           636:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
        !           637:   else if (optype1 == OFFSOP)
        !           638:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
        !           639:   else if (optype1 == CNSTOP)
        !           640:     {
        !           641:       if (GET_CODE (operands[1]) == CONST_DOUBLE)
        !           642:        split_double (operands[1], &operands[1], &latehalf[1]);
        !           643:       else if (CONSTANT_P (operands[1]))
        !           644:        latehalf[1] = const0_rtx;
        !           645:     }
        !           646:   else
        !           647:     latehalf[1] = operands[1];
        !           648: 
        !           649:   /* If the first move would clobber the source of the second one,
        !           650:      do them in the other order.
        !           651: 
        !           652:      RMS says "This happens only for registers;
        !           653:      such overlap can't happen in memory unless the user explicitly
        !           654:      sets it up, and that is an undefined circumstance."
        !           655: 
        !           656:      but it happens on the sparc when loading parameter registers,
        !           657:      so I am going to define that circumstance, and make it work
        !           658:      as expected.  */
        !           659: 
        !           660:   if (optype0 == REGOP && optype1 == REGOP
        !           661:       && REGNO (operands[0]) == REGNO (latehalf[1]))
        !           662:     {
        !           663:       CC_STATUS_PARTIAL_INIT;
        !           664:       /* Make any unoffsettable addresses point at high-numbered word.  */
        !           665:       if (addreg0)
        !           666:        output_asm_insn ("adds 0x4,%0,%0", &addreg0);
        !           667:       if (addreg1)
        !           668:        output_asm_insn ("adds 0x4,%0,%0", &addreg1);
        !           669: 
        !           670:       /* Do that word.  */
        !           671:       output_asm_insn (singlemove_string (latehalf), latehalf);
        !           672: 
        !           673:       /* Undo the adds we just did.  */
        !           674:       if (addreg0)
        !           675:        output_asm_insn ("adds -0x4,%0,%0", &addreg0);
        !           676:       if (addreg1)
        !           677:        output_asm_insn ("adds -0x4,%0,%0", &addreg1);
        !           678: 
        !           679:       /* Do low-numbered word.  */
        !           680:       return singlemove_string (operands);
        !           681:     }
        !           682:   else if (optype0 == REGOP && optype1 != REGOP
        !           683:           && reg_overlap_mentioned_p (operands[0], operands[1]))
        !           684:     {
        !           685:       /* If both halves of dest are used in the src memory address,
        !           686:         add the two regs and put them in the low reg (operands[0]).
        !           687:         Then it works to load latehalf first.  */
        !           688:       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
        !           689:          && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
        !           690:        {
        !           691:          rtx xops[2];
        !           692:          xops[0] = latehalf[0];
        !           693:          xops[1] = operands[0];
        !           694:          output_asm_insn ("adds %1,%0,%1", xops);
        !           695:          operands[1] = gen_rtx (MEM, DImode, operands[0]);
        !           696:          latehalf[1] = adj_offsettable_operand (operands[1], 4);
        !           697:          addreg1 = 0;
        !           698:          highest_first = 1;
        !           699:        }
        !           700:       /* Only one register in the dest is used in the src memory address,
        !           701:         and this is the first register of the dest, so we want to do
        !           702:         the late half first here also.  */
        !           703:       else if (! reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
        !           704:        highest_first = 1;
        !           705:       /* Only one register in the dest is used in the src memory address,
        !           706:         and this is the second register of the dest, so we want to do
        !           707:         the late half last.  If addreg1 is set, and addreg1 is the same
        !           708:         register as latehalf, then we must suppress the trailing decrement,
        !           709:         because it would clobber the value just loaded.  */
        !           710:       else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0]))
        !           711:        no_addreg1_decrement = 1;
        !           712:     }
        !           713: 
        !           714:   /* Normal case: do the two words, low-numbered first.
        !           715:      Overlap case (highest_first set): do high-numbered word first.  */
        !           716: 
        !           717:   if (! highest_first)
        !           718:     output_asm_insn (singlemove_string (operands), operands);
        !           719: 
        !           720:   CC_STATUS_PARTIAL_INIT;
        !           721:   /* Make any unoffsettable addresses point at high-numbered word.  */
        !           722:   if (addreg0)
        !           723:     output_asm_insn ("adds 0x4,%0,%0", &addreg0);
        !           724:   if (addreg1)
        !           725:     output_asm_insn ("adds 0x4,%0,%0", &addreg1);
        !           726: 
        !           727:   /* Do that word.  */
        !           728:   output_asm_insn (singlemove_string (latehalf), latehalf);
        !           729: 
        !           730:   /* Undo the adds we just did.  */
        !           731:   if (addreg0)
        !           732:     output_asm_insn ("adds -0x4,%0,%0", &addreg0);
        !           733:   if (addreg1 && !no_addreg1_decrement)
        !           734:     output_asm_insn ("adds -0x4,%0,%0", &addreg1);
        !           735: 
        !           736:   if (highest_first)
        !           737:     output_asm_insn (singlemove_string (operands), operands);
        !           738: 
        !           739:   return "";
        !           740: }
        !           741: 
        !           742: char *
        !           743: output_fp_move_double (operands)
        !           744:      rtx *operands;
        !           745: {
        !           746:   /* If the source operand is any sort of zero, use f0 instead.  */
        !           747: 
        !           748:   if (operands[1] == CONST0_RTX (GET_MODE (operands[1])))
        !           749:     operands[1] = gen_rtx (REG, DFmode, F0_REGNUM);
        !           750: 
        !           751:   if (FP_REG_P (operands[0]))
        !           752:     {
        !           753:       if (FP_REG_P (operands[1]))
        !           754:        return "fmov.dd %1,%0";
        !           755:       if (GET_CODE (operands[1]) == REG)
        !           756:        {
        !           757:          output_asm_insn ("ixfr %1,%0", operands);
        !           758:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
        !           759:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
        !           760:          return "ixfr %1,%0";
        !           761:        }
        !           762:       if (operands[1] == CONST0_RTX (DFmode))
        !           763:        return "fmov.dd f0,%0";
        !           764:       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
        !           765:        {
        !           766:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !           767:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !           768:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
        !           769:            {
        !           770:              CC_STATUS_INIT;
        !           771:              output_asm_insn ("orh %h1,%?r0,%?r31", operands);
        !           772:            }
        !           773:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
        !           774:          cc_status.mdep = XEXP (operands[1], 0);
        !           775:          return "fld.d %L1(%?r31),%0";
        !           776:        }
        !           777:       return "fld.d %1,%0";
        !           778:     }
        !           779:   else if (FP_REG_P (operands[1]))
        !           780:     {
        !           781:       if (GET_CODE (operands[0]) == REG)
        !           782:        {
        !           783:          output_asm_insn ("fxfr %1,%0", operands);
        !           784:          operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
        !           785:          operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
        !           786:          return "fxfr %1,%0";
        !           787:        }
        !           788:       if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
        !           789:        {
        !           790:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !           791:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !           792:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
        !           793:            {
        !           794:              CC_STATUS_INIT;
        !           795:              output_asm_insn ("orh %h0,%?r0,%?r31", operands);
        !           796:            }
        !           797:          cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
        !           798:          cc_status.mdep = XEXP (operands[0], 0);
        !           799:          return "fst.d %1,%L0(%?r31)";
        !           800:        }
        !           801:       return "fst.d %1,%0";
        !           802:     }
        !           803:   else
        !           804:     abort ();
        !           805:   /* NOTREACHED */
        !           806:   return NULL;
        !           807: }
        !           808: 
        !           809: /* Return a REG that occurs in ADDR with coefficient 1.
        !           810:    ADDR can be effectively incremented by incrementing REG.  */
        !           811: 
        !           812: static rtx
        !           813: find_addr_reg (addr)
        !           814:      rtx addr;
        !           815: {
        !           816:   while (GET_CODE (addr) == PLUS)
        !           817:     {
        !           818:       if (GET_CODE (XEXP (addr, 0)) == REG)
        !           819:        addr = XEXP (addr, 0);
        !           820:       else if (GET_CODE (XEXP (addr, 1)) == REG)
        !           821:        addr = XEXP (addr, 1);
        !           822:       else if (CONSTANT_P (XEXP (addr, 0)))
        !           823:        addr = XEXP (addr, 1);
        !           824:       else if (CONSTANT_P (XEXP (addr, 1)))
        !           825:        addr = XEXP (addr, 0);
        !           826:       else
        !           827:        abort ();
        !           828:     }
        !           829:   if (GET_CODE (addr) == REG)
        !           830:     return addr;
        !           831:   abort ();
        !           832:   /* NOTREACHED */
        !           833:   return NULL;
        !           834: }
        !           835: 
        !           836: /* Return a template for a load instruction with mode MODE and
        !           837:    arguments from the string ARGS.
        !           838: 
        !           839:    This string is in static storage.   */
        !           840: 
        !           841: static char *
        !           842: load_opcode (mode, args, reg)
        !           843:      enum machine_mode mode;
        !           844:      char *args;
        !           845:      rtx reg;
        !           846: {
        !           847:   static char buf[30];
        !           848:   char *opcode;
        !           849: 
        !           850:   switch (mode)
        !           851:     {
        !           852:     case QImode:
        !           853:       opcode = "ld.b";
        !           854:       break;
        !           855: 
        !           856:     case HImode:
        !           857:       opcode = "ld.s";
        !           858:       break;
        !           859: 
        !           860:     case SImode:
        !           861:     case SFmode:
        !           862:       if (FP_REG_P (reg))
        !           863:        opcode = "fld.l";
        !           864:       else
        !           865:        opcode = "ld.l";
        !           866:       break;
        !           867: 
        !           868:     case DImode:
        !           869:       if (!FP_REG_P (reg))
        !           870:        abort ();
        !           871:     case DFmode:
        !           872:       opcode = "fld.d";
        !           873:       break;
        !           874: 
        !           875:     default:
        !           876:       abort ();
        !           877:     }
        !           878: 
        !           879:   sprintf (buf, "%s %s", opcode, args);
        !           880:   return buf;
        !           881: }
        !           882: 
        !           883: /* Return a template for a store instruction with mode MODE and
        !           884:    arguments from the string ARGS.
        !           885: 
        !           886:    This string is in static storage.   */
        !           887: 
        !           888: static char *
        !           889: store_opcode (mode, args, reg)
        !           890:      enum machine_mode mode;
        !           891:      char *args;
        !           892:      rtx reg;
        !           893: {
        !           894:   static char buf[30];
        !           895:   char *opcode;
        !           896: 
        !           897:   switch (mode)
        !           898:     {
        !           899:     case QImode:
        !           900:       opcode = "st.b";
        !           901:       break;
        !           902: 
        !           903:     case HImode:
        !           904:       opcode = "st.s";
        !           905:       break;
        !           906: 
        !           907:     case SImode:
        !           908:     case SFmode:
        !           909:       if (FP_REG_P (reg))
        !           910:        opcode = "fst.l";
        !           911:       else
        !           912:        opcode = "st.l";
        !           913:       break;
        !           914: 
        !           915:     case DImode:
        !           916:       if (!FP_REG_P (reg))
        !           917:        abort ();
        !           918:     case DFmode:
        !           919:       opcode = "fst.d";
        !           920:       break;
        !           921: 
        !           922:     default:
        !           923:       abort ();
        !           924:     }
        !           925: 
        !           926:   sprintf (buf, "%s %s", opcode, args);
        !           927:   return buf;
        !           928: }
        !           929: 
        !           930: /* Output a store-in-memory whose operands are OPERANDS[0,1].
        !           931:    OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
        !           932: 
        !           933:    This function returns a template for an insn.
        !           934:    This is in static storage.
        !           935: 
        !           936:    It may also output some insns directly.
        !           937:    It may alter the values of operands[0] and operands[1].  */
        !           938: 
        !           939: char *
        !           940: output_store (operands)
        !           941:      rtx *operands;
        !           942: {
        !           943:   enum machine_mode mode = GET_MODE (operands[0]);
        !           944:   rtx address = XEXP (operands[0], 0);
        !           945:   char *string;
        !           946: 
        !           947:   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
        !           948:   cc_status.mdep = address;
        !           949: 
        !           950:   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !           951:         && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !           952:         && address == cc_prev_status.mdep))
        !           953:     {
        !           954:       CC_STATUS_INIT;
        !           955:       output_asm_insn ("orh %h0,%?r0,%?r31", operands);
        !           956:       cc_prev_status.mdep = address;
        !           957:     }
        !           958: 
        !           959:   /* Store zero in two parts when appropriate.  */
        !           960:   if (mode == DFmode && operands[1] == CONST0_RTX (DFmode))
        !           961:     return store_opcode (DFmode, "%r1,%L0(%?r31)", operands[1]);
        !           962: 
        !           963:   /* Code below isn't smart enough to move a doubleword in two parts,
        !           964:      so use output_move_double to do that in the cases that require it.  */
        !           965:   if ((mode == DImode || mode == DFmode)
        !           966:       && ! FP_REG_P (operands[1]))
        !           967:     return output_move_double (operands);
        !           968: 
        !           969:   return store_opcode (mode, "%r1,%L0(%?r31)", operands[1]);
        !           970: }
        !           971: 
        !           972: /* Output a load-from-memory whose operands are OPERANDS[0,1].
        !           973:    OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
        !           974: 
        !           975:    This function returns a template for an insn.
        !           976:    This is in static storage.
        !           977: 
        !           978:    It may also output some insns directly.
        !           979:    It may alter the values of operands[0] and operands[1].  */
        !           980: 
        !           981: char *
        !           982: output_load (operands)
        !           983:      rtx *operands;
        !           984: {
        !           985:   enum machine_mode mode = GET_MODE (operands[0]);
        !           986:   rtx address = XEXP (operands[1], 0);
        !           987: 
        !           988:   /* We don't bother trying to see if we know %hi(address).
        !           989:      This is because we are doing a load, and if we know the
        !           990:      %hi value, we probably also know that value in memory.  */
        !           991:   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
        !           992:   cc_status.mdep = address;
        !           993: 
        !           994:   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !           995:         && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !           996:         && address == cc_prev_status.mdep
        !           997:         && cc_prev_status.mdep == cc_status.mdep))
        !           998:     {
        !           999:       CC_STATUS_INIT;
        !          1000:       output_asm_insn ("orh %h1,%?r0,%?r31", operands);
        !          1001:       cc_prev_status.mdep = address;
        !          1002:     }
        !          1003: 
        !          1004:   /* Code below isn't smart enough to move a doubleword in two parts,
        !          1005:      so use output_move_double to do that in the cases that require it.  */
        !          1006:   if ((mode == DImode || mode == DFmode)
        !          1007:       && ! FP_REG_P (operands[0]))
        !          1008:     return output_move_double (operands);
        !          1009: 
        !          1010:   return load_opcode (mode, "%L1(%?r31),%0", operands[0]);
        !          1011: }
        !          1012: 
        !          1013: #if 0
        !          1014: /* Load the address specified by OPERANDS[3] into the register
        !          1015:    specified by OPERANDS[0].
        !          1016: 
        !          1017:    OPERANDS[3] may be the result of a sum, hence it could either be:
        !          1018: 
        !          1019:    (1) CONST
        !          1020:    (2) REG
        !          1021:    (2) REG + CONST_INT
        !          1022:    (3) REG + REG + CONST_INT
        !          1023:    (4) REG + REG  (special case of 3).
        !          1024: 
        !          1025:    Note that (3) is not a legitimate address.
        !          1026:    All cases are handled here.  */
        !          1027: 
        !          1028: void
        !          1029: output_load_address (operands)
        !          1030:      rtx *operands;
        !          1031: {
        !          1032:   rtx base, offset;
        !          1033: 
        !          1034:   if (CONSTANT_P (operands[3]))
        !          1035:     {
        !          1036:       output_asm_insn ("mov %3,%0", operands);
        !          1037:       return;
        !          1038:     }
        !          1039: 
        !          1040:   if (REG_P (operands[3]))
        !          1041:     {
        !          1042:       if (REGNO (operands[0]) != REGNO (operands[3]))
        !          1043:        output_asm_insn ("shl %?r0,%3,%0", operands);
        !          1044:       return;
        !          1045:     }
        !          1046: 
        !          1047:   if (GET_CODE (operands[3]) != PLUS)
        !          1048:     abort ();
        !          1049: 
        !          1050:   base = XEXP (operands[3], 0);
        !          1051:   offset = XEXP (operands[3], 1);
        !          1052: 
        !          1053:   if (GET_CODE (base) == CONST_INT)
        !          1054:     {
        !          1055:       rtx tmp = base;
        !          1056:       base = offset;
        !          1057:       offset = tmp;
        !          1058:     }
        !          1059: 
        !          1060:   if (GET_CODE (offset) != CONST_INT)
        !          1061:     {
        !          1062:       /* Operand is (PLUS (REG) (REG)).  */
        !          1063:       base = operands[3];
        !          1064:       offset = const0_rtx;
        !          1065:     }
        !          1066: 
        !          1067:   if (REG_P (base))
        !          1068:     {
        !          1069:       operands[6] = base;
        !          1070:       operands[7] = offset;
        !          1071:       CC_STATUS_PARTIAL_INIT;
        !          1072:       if (SMALL_INT (offset))
        !          1073:        output_asm_insn ("adds %7,%6,%0", operands);
        !          1074:       else
        !          1075:        output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
        !          1076:     }
        !          1077:   else if (GET_CODE (base) == PLUS)
        !          1078:     {
        !          1079:       operands[6] = XEXP (base, 0);
        !          1080:       operands[7] = XEXP (base, 1);
        !          1081:       operands[8] = offset;
        !          1082: 
        !          1083:       CC_STATUS_PARTIAL_INIT;
        !          1084:       if (SMALL_INT (offset))
        !          1085:        output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
        !          1086:       else
        !          1087:        output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
        !          1088:     }
        !          1089:   else
        !          1090:     abort ();
        !          1091: }
        !          1092: #endif
        !          1093: 
        !          1094: /* Output code to place a size count SIZE in register REG.
        !          1095:    Because block moves are pipelined, we don't include the
        !          1096:    first element in the transfer of SIZE to REG.
        !          1097:    For this, we subtract ALIGN.  (Actually, I think it is not
        !          1098:    right to subtract on this machine, so right now we don't.)  */
        !          1099: 
        !          1100: static void
        !          1101: output_size_for_block_move (size, reg, align)
        !          1102:      rtx size, reg, align;
        !          1103: {
        !          1104:   rtx xoperands[3];
        !          1105: 
        !          1106:   xoperands[0] = reg;
        !          1107:   xoperands[1] = size;
        !          1108:   xoperands[2] = align;
        !          1109: 
        !          1110: #if 1
        !          1111:   cc_status.flags &= ~ CC_KNOW_HI_R31;
        !          1112:   output_asm_insn (singlemove_string (xoperands), xoperands);
        !          1113: #else
        !          1114:   if (GET_CODE (size) == REG)
        !          1115:     output_asm_insn ("sub %2,%1,%0", xoperands);
        !          1116:   else
        !          1117:     {
        !          1118:       xoperands[1]
        !          1119:        = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
        !          1120:       cc_status.flags &= ~ CC_KNOW_HI_R31;
        !          1121:       output_asm_insn ("mov %1,%0", xoperands);
        !          1122:     }
        !          1123: #endif
        !          1124: }
        !          1125: 
        !          1126: /* Emit code to perform a block move.
        !          1127: 
        !          1128:    OPERANDS[0] is the destination.
        !          1129:    OPERANDS[1] is the source.
        !          1130:    OPERANDS[2] is the size.
        !          1131:    OPERANDS[3] is the known safe alignment.
        !          1132:    OPERANDS[4..6] are pseudos we can safely clobber as temps.  */
        !          1133: 
        !          1134: char *
        !          1135: output_block_move (operands)
        !          1136:      rtx *operands;
        !          1137: {
        !          1138:   /* A vector for our computed operands.  Note that load_output_address
        !          1139:      makes use of (and can clobber) up to the 8th element of this vector.  */
        !          1140:   rtx xoperands[10];
        !          1141:   rtx zoperands[10];
        !          1142:   static int movstrsi_label = 0;
        !          1143:   int i, j;
        !          1144:   rtx temp1 = operands[4];
        !          1145:   rtx alignrtx = operands[3];
        !          1146:   int align = INTVAL (alignrtx);
        !          1147:   int chunk_size;
        !          1148: 
        !          1149:   xoperands[0] = operands[0];
        !          1150:   xoperands[1] = operands[1];
        !          1151:   xoperands[2] = temp1;
        !          1152: 
        !          1153:   /* We can't move more than four bytes at a time
        !          1154:      because we have only one register to move them through.  */
        !          1155:   if (align > 4)
        !          1156:     {
        !          1157:       align = 4;
        !          1158:       alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
        !          1159:     }
        !          1160: 
        !          1161:   /* Recognize special cases of block moves.  These occur
        !          1162:      when GNU C++ is forced to treat something as BLKmode
        !          1163:      to keep it in memory, when its mode could be represented
        !          1164:      with something smaller.
        !          1165: 
        !          1166:      We cannot do this for global variables, since we don't know
        !          1167:      what pages they don't cross.  Sigh.  */
        !          1168:   if (GET_CODE (operands[2]) == CONST_INT
        !          1169:       && ! CONSTANT_ADDRESS_P (operands[0])
        !          1170:       && ! CONSTANT_ADDRESS_P (operands[1]))
        !          1171:     {
        !          1172:       int size = INTVAL (operands[2]);
        !          1173:       rtx op0 = xoperands[0];
        !          1174:       rtx op1 = xoperands[1];
        !          1175: 
        !          1176:       if ((align & 3) == 0 && (size & 3) == 0 && (size >> 2) <= 16)
        !          1177:        {
        !          1178:          if (memory_address_p (SImode, plus_constant (op0, size))
        !          1179:              && memory_address_p (SImode, plus_constant (op1, size)))
        !          1180:            {
        !          1181:              cc_status.flags &= ~CC_KNOW_HI_R31;
        !          1182:              for (i = (size>>2)-1; i >= 0; i--)
        !          1183:                {
        !          1184:                  xoperands[0] = plus_constant (op0, i * 4);
        !          1185:                  xoperands[1] = plus_constant (op1, i * 4);
        !          1186:                  output_asm_insn ("ld.l %a1,%?r31\n\tst.l %?r31,%a0",
        !          1187:                                   xoperands);
        !          1188:                }
        !          1189:              return "";
        !          1190:            }
        !          1191:        }
        !          1192:       else if ((align & 1) == 0 && (size & 1) == 0 && (size >> 1) <= 16)
        !          1193:        {
        !          1194:          if (memory_address_p (HImode, plus_constant (op0, size))
        !          1195:              && memory_address_p (HImode, plus_constant (op1, size)))
        !          1196:            {
        !          1197:              cc_status.flags &= ~CC_KNOW_HI_R31;
        !          1198:              for (i = (size>>1)-1; i >= 0; i--)
        !          1199:                {
        !          1200:                  xoperands[0] = plus_constant (op0, i * 2);
        !          1201:                  xoperands[1] = plus_constant (op1, i * 2);
        !          1202:                  output_asm_insn ("ld.s %a1,%?r31\n\tst.s %?r31,%a0",
        !          1203:                                   xoperands);
        !          1204:                }
        !          1205:              return "";
        !          1206:            }
        !          1207:        }
        !          1208:       else if (size <= 16)
        !          1209:        {
        !          1210:          if (memory_address_p (QImode, plus_constant (op0, size))
        !          1211:              && memory_address_p (QImode, plus_constant (op1, size)))
        !          1212:            {
        !          1213:              cc_status.flags &= ~CC_KNOW_HI_R31;
        !          1214:              for (i = size-1; i >= 0; i--)
        !          1215:                {
        !          1216:                  xoperands[0] = plus_constant (op0, i);
        !          1217:                  xoperands[1] = plus_constant (op1, i);
        !          1218:                  output_asm_insn ("ld.b %a1,%?r31\n\tst.b %?r31,%a0",
        !          1219:                                   xoperands);
        !          1220:                }
        !          1221:              return "";
        !          1222:            }
        !          1223:        }
        !          1224:     }
        !          1225: 
        !          1226:   /* Since we clobber untold things, nix the condition codes.  */
        !          1227:   CC_STATUS_INIT;
        !          1228: 
        !          1229:   /* This is the size of the transfer.
        !          1230:      Either use the register which already contains the size,
        !          1231:      or use a free register (used by no operands).  */
        !          1232:   output_size_for_block_move (operands[2], operands[4], alignrtx);
        !          1233: 
        !          1234: #if 0
        !          1235:   /* Also emit code to decrement the size value by ALIGN.  */
        !          1236:   zoperands[0] = operands[0];
        !          1237:   zoperands[3] = plus_constant (operands[0], align);
        !          1238:   output_load_address (zoperands);
        !          1239: #endif
        !          1240: 
        !          1241:   /* Generate number for unique label.  */
        !          1242: 
        !          1243:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
        !          1244: 
        !          1245:   /* Calculate the size of the chunks we will be trying to move first.  */
        !          1246: 
        !          1247: #if 0
        !          1248:   if ((align & 3) == 0)
        !          1249:     chunk_size = 4;
        !          1250:   else if ((align & 1) == 0)
        !          1251:     chunk_size = 2;
        !          1252:   else
        !          1253: #endif
        !          1254:     chunk_size = 1;
        !          1255: 
        !          1256:   /* Copy the increment (negative) to a register for bla insn.  */
        !          1257: 
        !          1258:   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - chunk_size);
        !          1259:   xoperands[5] = operands[5];
        !          1260:   output_asm_insn ("adds %4,%?r0,%5", xoperands);
        !          1261: 
        !          1262:   /* Predecrement the loop counter.  This happens again also in the `bla'
        !          1263:      instruction which precedes the loop, but we need to have it done
        !          1264:      two times before we enter the loop because of the bizarre semantics
        !          1265:      of the bla instruction.  */
        !          1266: 
        !          1267:   output_asm_insn ("adds %5,%2,%2", xoperands);
        !          1268: 
        !          1269:   /* Check for the case where the original count was less than or equal to
        !          1270:      zero.  Avoid going through the loop at all if the original count was
        !          1271:      indeed less than or equal to zero.  Note that we treat the count as
        !          1272:      if it were a signed 32-bit quantity here, rather than an unsigned one,
        !          1273:      even though we really shouldn't.  We have to do this because of the
        !          1274:      semantics of the `ble' instruction, which assume that the count is
        !          1275:      a signed 32-bit value.  Anyway, in practice it won't matter because
        !          1276:      nobody is going to try to do a memcpy() of more than half of the
        !          1277:      entire address space (i.e. 2 gigabytes) anyway.  */
        !          1278: 
        !          1279:   output_asm_insn ("bc .Le%3", xoperands);
        !          1280: 
        !          1281:   /* Make available a register which is a temporary.  */
        !          1282: 
        !          1283:   xoperands[6] = operands[6];
        !          1284: 
        !          1285:   /* Now the actual loop.
        !          1286:      In xoperands, elements 1 and 0 are the input and output vectors.
        !          1287:      Element 2 is the loop index.  Element 5 is the increment.  */
        !          1288: 
        !          1289:   output_asm_insn ("subs %1,%5,%1", xoperands);
        !          1290:   output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
        !          1291:   output_asm_insn ("adds %0,%2,%6", xoperands);
        !          1292:   output_asm_insn ("\n.Lm%3:", xoperands);         /* Label for bla above.  */
        !          1293:   output_asm_insn ("\n.Ls%3:",  xoperands);        /* Loop start label. */
        !          1294:   output_asm_insn ("adds %5,%6,%6", xoperands);
        !          1295: 
        !          1296:   /* NOTE:  The code here which is supposed to handle the cases where the
        !          1297:      sources and destinations are known to start on a 4 or 2 byte boundary
        !          1298:      are currently broken.  They fail to do anything about the overflow
        !          1299:      bytes which might still need to be copied even after we have copied
        !          1300:      some number of words or halfwords.  Thus, for now we use the lowest
        !          1301:      common denominator, i.e. the code which just copies some number of
        !          1302:      totally unaligned individual bytes.  (See the calculation of
        !          1303:      chunk_size above.  */
        !          1304: 
        !          1305:   if (chunk_size == 4)
        !          1306:     {
        !          1307:       output_asm_insn ("ld.l %2(%1),%?r31", xoperands);
        !          1308:       output_asm_insn ("bla %5,%2,.Ls%3", xoperands);
        !          1309:       output_asm_insn ("st.l %?r31,8(%6)", xoperands);
        !          1310:     }
        !          1311:   else if (chunk_size == 2)
        !          1312:     {
        !          1313:       output_asm_insn ("ld.s %2(%1),%?r31", xoperands);
        !          1314:       output_asm_insn ("bla %5,%2,.Ls%3", xoperands);
        !          1315:       output_asm_insn ("st.s %?r31,4(%6)", xoperands);
        !          1316:     }
        !          1317:   else /* chunk_size == 1 */
        !          1318:     {
        !          1319:       output_asm_insn ("ld.b %2(%1),%?r31", xoperands);
        !          1320:       output_asm_insn ("bla %5,%2,.Ls%3", xoperands);
        !          1321:       output_asm_insn ("st.b %?r31,2(%6)", xoperands);
        !          1322:     }
        !          1323:   output_asm_insn ("\n.Le%3:", xoperands);         /* Here if count <= 0.  */
        !          1324: 
        !          1325:   return "";
        !          1326: }
        !          1327: 
        !          1328: /* Output a delayed branch insn with the delay insn in its
        !          1329:    branch slot.  The delayed branch insn template is in TEMPLATE,
        !          1330:    with operands OPERANDS.  The insn in its delay slot is INSN.
        !          1331: 
        !          1332:    As a special case, since we know that all memory transfers are via
        !          1333:    ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
        !          1334:    reference around the branch as
        !          1335: 
        !          1336:        orh ha%x,%?r0,%?r31
        !          1337:        b ...
        !          1338:        ld/st l%x(%?r31),...
        !          1339: 
        !          1340:    As another special case, we handle loading (SYMBOL_REF ...) and
        !          1341:    other large constants around branches as well:
        !          1342: 
        !          1343:        orh h%x,%?r0,%0
        !          1344:        b ...
        !          1345:        or l%x,%0,%1
        !          1346: 
        !          1347:    */
        !          1348: 
        !          1349: char *
        !          1350: output_delayed_branch (template, operands, insn)
        !          1351:      char *template;
        !          1352:      rtx *operands;
        !          1353:      rtx insn;
        !          1354: {
        !          1355:   rtx src = XVECEXP (PATTERN (insn), 0, 1);
        !          1356:   rtx dest = XVECEXP (PATTERN (insn), 0, 0);
        !          1357: 
        !          1358:   /* See if we are doing some branch together with setting some register
        !          1359:      to some 32-bit value which does (or may) have some of the high-order
        !          1360:      16 bits set.  If so, we need to set the register in two stages.  One
        !          1361:      stage must be done before the branch, and the other one can be done
        !          1362:      in the delay slot.  */
        !          1363: 
        !          1364:   if ( (GET_CODE (src) == CONST_INT
        !          1365:        && ((unsigned) INTVAL (src) & (unsigned) 0xffff0000) != (unsigned) 0)
        !          1366:       || (GET_CODE (src) == SYMBOL_REF)
        !          1367:       || (GET_CODE (src) == LABEL_REF)
        !          1368:       || (GET_CODE (src) == CONST))
        !          1369:     {
        !          1370:       rtx xoperands[2];
        !          1371:       xoperands[0] = dest;
        !          1372:       xoperands[1] = src;
        !          1373: 
        !          1374:       CC_STATUS_PARTIAL_INIT;
        !          1375:       /* Output the `orh' insn.  */
        !          1376:       output_asm_insn ("orh %H1,%?r0,%0", xoperands);
        !          1377: 
        !          1378:       /* Output the branch instruction next.  */
        !          1379:       output_asm_insn (template, operands);
        !          1380: 
        !          1381:       /* Now output the `or' insn.  */
        !          1382:       output_asm_insn ("or %L1,%0,%0", xoperands);
        !          1383:     }
        !          1384:   else if ((GET_CODE (src) == MEM
        !          1385:            && CONSTANT_ADDRESS_P (XEXP (src, 0)))
        !          1386:           || (GET_CODE (dest) == MEM
        !          1387:               && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
        !          1388:     {
        !          1389:       rtx xoperands[2];
        !          1390:       char *split_template;
        !          1391:       xoperands[0] = dest;
        !          1392:       xoperands[1] = src;
        !          1393: 
        !          1394:       /* Output the `orh' insn.  */
        !          1395:       if (GET_CODE (src) == MEM)
        !          1396:        {
        !          1397:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !          1398:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !          1399:                 && cc_prev_status.mdep == XEXP (operands[1], 0)))
        !          1400:            {
        !          1401:              CC_STATUS_INIT;
        !          1402:              output_asm_insn ("orh %h1,%?r0,%?r31", xoperands);
        !          1403:            }
        !          1404:          split_template = load_opcode (GET_MODE (dest),
        !          1405:                                        "%L1(%?r31),%0", dest);
        !          1406:        }
        !          1407:       else
        !          1408:        {
        !          1409:          if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
        !          1410:                 && (cc_prev_status.flags & CC_HI_R31_ADJ)
        !          1411:                 && cc_prev_status.mdep == XEXP (operands[0], 0)))
        !          1412:            {
        !          1413:              CC_STATUS_INIT;
        !          1414:              output_asm_insn ("orh %h0,%?r0,%?r31", xoperands);
        !          1415:            }
        !          1416:          split_template = store_opcode (GET_MODE (dest),
        !          1417:                                         "%r1,%L0(%?r31)", src);
        !          1418:        }
        !          1419: 
        !          1420:       /* Output the branch instruction next.  */
        !          1421:       output_asm_insn (template, operands);
        !          1422: 
        !          1423:       /* Now output the load or store.
        !          1424:         No need to do a CC_STATUS_INIT, because we are branching anyway.  */
        !          1425:       output_asm_insn (split_template, xoperands);
        !          1426:     }
        !          1427:   else
        !          1428:     {
        !          1429:       int insn_code_number;
        !          1430:       rtx pat = gen_rtx (SET, VOIDmode, dest, src);
        !          1431:       rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
        !          1432:       int i;
        !          1433: 
        !          1434:       /* Output the branch instruction first.  */
        !          1435:       output_asm_insn (template, operands);
        !          1436: 
        !          1437:       /* Now recognize the insn which we put in its delay slot.
        !          1438:         We must do this after outputting the branch insn,
        !          1439:         since operands may just be a pointer to `recog_operand'.  */
        !          1440:       INSN_CODE (delay_insn) = insn_code_number = recog (pat, delay_insn);
        !          1441:       if (insn_code_number == -1)
        !          1442:        abort ();
        !          1443: 
        !          1444:       for (i = 0; i < insn_n_operands[insn_code_number]; i++)
        !          1445:        {
        !          1446:          if (GET_CODE (recog_operand[i]) == SUBREG)
        !          1447:            recog_operand[i] = alter_subreg (recog_operand[i]);
        !          1448:        }
        !          1449: 
        !          1450:       insn_extract (delay_insn);
        !          1451:       if (! constrain_operands (insn_code_number, 1))
        !          1452:        fatal_insn_not_found (delay_insn);
        !          1453: 
        !          1454:       template = insn_template[insn_code_number];
        !          1455:       if (template == 0)
        !          1456:        template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
        !          1457:       output_asm_insn (template, recog_operand);
        !          1458:     }
        !          1459:   CC_STATUS_INIT;
        !          1460:   return "";
        !          1461: }
        !          1462: 
        !          1463: /* Output a newly constructed insn DELAY_INSN.  */
        !          1464: char *
        !          1465: output_delay_insn (delay_insn)
        !          1466:      rtx delay_insn;
        !          1467: {
        !          1468:   char *template;
        !          1469:   int insn_code_number;
        !          1470:   int i;
        !          1471: 
        !          1472:   /* Now recognize the insn which we put in its delay slot.
        !          1473:      We must do this after outputting the branch insn,
        !          1474:      since operands may just be a pointer to `recog_operand'.  */
        !          1475:   insn_code_number = recog_memoized (delay_insn);
        !          1476:   if (insn_code_number == -1)
        !          1477:     abort ();
        !          1478: 
        !          1479:   /* Extract the operands of this delay insn.  */
        !          1480:   INSN_CODE (delay_insn) = insn_code_number;
        !          1481:   insn_extract (delay_insn);
        !          1482: 
        !          1483:   /* It is possible that this insn has not been properly scanned by final
        !          1484:      yet.  If this insn's operands don't appear in the peephole's
        !          1485:      actual operands, then they won't be fixed up by final, so we
        !          1486:      make sure they get fixed up here.  -- This is a kludge.  */
        !          1487:   for (i = 0; i < insn_n_operands[insn_code_number]; i++)
        !          1488:     {
        !          1489:       if (GET_CODE (recog_operand[i]) == SUBREG)
        !          1490:        recog_operand[i] = alter_subreg (recog_operand[i]);
        !          1491:     }
        !          1492: 
        !          1493: #ifdef REGISTER_CONSTRAINTS
        !          1494:   if (! constrain_operands (insn_code_number))
        !          1495:     abort ();
        !          1496: #endif
        !          1497: 
        !          1498:   cc_prev_status = cc_status;
        !          1499: 
        !          1500:   /* Update `cc_status' for this instruction.
        !          1501:      The instruction's output routine may change it further.
        !          1502:      If the output routine for a jump insn needs to depend
        !          1503:      on the cc status, it should look at cc_prev_status.  */
        !          1504: 
        !          1505:   NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
        !          1506: 
        !          1507:   /* Now get the template for what this insn would
        !          1508:      have been, without the branch.  */
        !          1509: 
        !          1510:   template = insn_template[insn_code_number];
        !          1511:   if (template == 0)
        !          1512:     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
        !          1513:   output_asm_insn (template, recog_operand);
        !          1514:   return "";
        !          1515: }
        !          1516: 
        !          1517: /* Special routine to convert an SFmode value represented as a
        !          1518:    CONST_DOUBLE into its equivalent unsigned long bit pattern.
        !          1519:    We convert the value from a double precision floating-point
        !          1520:    value to single precision first, and thence to a bit-wise
        !          1521:    equivalent unsigned long value.  This routine is used when
        !          1522:    generating an immediate move of an SFmode value directly
        !          1523:    into a general register because the svr4 assembler doesn't
        !          1524:    grok floating literals in instruction operand contexts.  */
        !          1525: 
        !          1526: unsigned long
        !          1527: sfmode_constant_to_ulong (x)
        !          1528:      rtx x;
        !          1529: {
        !          1530:   REAL_VALUE_TYPE d;
        !          1531:   union { float f; unsigned long i; } u2;
        !          1532: 
        !          1533:   if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != SFmode)
        !          1534:     abort ();
        !          1535: 
        !          1536: #if TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT
        !          1537:  error IEEE emulation needed
        !          1538: #endif
        !          1539:   REAL_VALUE_FROM_CONST_DOUBLE (d, x);
        !          1540:   u2.f = d;
        !          1541:   return u2.i;
        !          1542: }
        !          1543: 
        !          1544: /* This function generates the assembly code for function entry.
        !          1545:    The macro FUNCTION_PROLOGUE in i860.h is defined to call this function.
        !          1546: 
        !          1547:    ASM_FILE is a stdio stream to output the code to.
        !          1548:    SIZE is an int: how many units of temporary storage to allocate.
        !          1549: 
        !          1550:    Refer to the array `regs_ever_live' to determine which registers
        !          1551:    to save; `regs_ever_live[I]' is nonzero if register number I
        !          1552:    is ever used in the function.  This macro is responsible for
        !          1553:    knowing which registers should not be saved even if used.
        !          1554: 
        !          1555:    NOTE: `frame_lower_bytes' is the count of bytes which will lie
        !          1556:    between the new `fp' value and the new `sp' value after the
        !          1557:    prologue is done.  `frame_upper_bytes' is the count of bytes
        !          1558:    that will lie between the new `fp' and the *old* `sp' value
        !          1559:    after the new `fp' is setup (in the prologue).  The upper
        !          1560:    part of each frame always includes at least 2 words (8 bytes)
        !          1561:    to hold the saved frame pointer and the saved return address.
        !          1562: 
        !          1563:    The svr4 ABI for the i860 now requires that the values of the
        !          1564:    stack pointer and frame pointer registers be kept aligned to
        !          1565:    16-byte boundaries at all times.  We obey that restriction here.
        !          1566: 
        !          1567:    The svr4 ABI for the i860 is entirely vague when it comes to specifying
        !          1568:    exactly where the "preserved" registers should be saved.  The native
        !          1569:    svr4 C compiler I now have doesn't help to clarify the requirements
        !          1570:    very much because it is plainly out-of-date and non-ABI-compliant
        !          1571:    (in at least one important way, i.e. how it generates function
        !          1572:    epilogues).
        !          1573: 
        !          1574:    The native svr4 C compiler saves the "preserved" registers (i.e.
        !          1575:    r4-r15 and f2-f7) in the lower part of a frame (i.e. at negative
        !          1576:    offsets from the frame pointer).
        !          1577: 
        !          1578:    Previous versions of GCC also saved the "preserved" registers in the
        !          1579:    "negative" part of the frame, but they saved them using positive
        !          1580:    offsets from the (adjusted) stack pointer (after it had been adjusted
        !          1581:    to allocate space for the new frame).  That's just plain wrong
        !          1582:    because if the current function calls alloca(), the stack pointer
        !          1583:    will get moved, and it will be impossible to restore the registers
        !          1584:    properly again after that.
        !          1585: 
        !          1586:    Both compilers handled parameter registers (i.e. r16-r27 and f8-f15)
        !          1587:    by copying their values either into various "preserved" registers or
        !          1588:    into stack slots in the lower part of the current frame (as seemed
        !          1589:    appropriate, depending upon subsequent usage of these values).
        !          1590: 
        !          1591:    Here we want to save the preserved registers at some offset from the
        !          1592:    frame pointer register so as to avoid any possible problems arising
        !          1593:    from calls to alloca().  We can either save them at small positive
        !          1594:    offsets from the frame pointer, or at small negative offsets from
        !          1595:    the frame pointer.  If we save them at small negative offsets from
        !          1596:    the frame pointer (i.e. in the lower part of the frame) then we
        !          1597:    must tell the rest of GCC (via STARTING_FRAME_OFFSET) exactly how
        !          1598:    many bytes of space we plan to use in the lower part of the frame
        !          1599:    for this purpose.  Since other parts of the compiler reference the
        !          1600:    value of STARTING_FRAME_OFFSET long before final() calls this function,
        !          1601:    we would have to go ahead and assume the worst-case storage requirements
        !          1602:    for saving all of the "preserved" registers (and use that number, i.e.
        !          1603:    `80', to define STARTING_FRAME_OFFSET) if we wanted to save them in
        !          1604:    the lower part of the frame.  That could potentially be very wasteful,
        !          1605:    and that wastefulness could really hamper people compiling for embedded
        !          1606:    i860 targets with very tight limits on stack space.  Thus, we choose
        !          1607:    here to save the preserved registers in the upper part of the
        !          1608:    frame, so that we can decide at the very last minute how much (or how
        !          1609:    little) space we must allocate for this purpose.
        !          1610: 
        !          1611:    To satisfy the needs of the svr4 ABI "tdesc" scheme, preserved
        !          1612:    registers must always be saved so that the saved values of registers
        !          1613:    with higher numbers are at higher addresses.  We obey that restriction
        !          1614:    here.
        !          1615: 
        !          1616:    There are two somewhat different ways that you can generate prologues
        !          1617:    here... i.e. pedantically ABI-compliant, and the "other" way.  The
        !          1618:    "other" way is more consistent with what is currently generated by the
        !          1619:    "native" svr4 C compiler for the i860.  That's important if you want
        !          1620:    to use the current (as of 8/91) incarnation of svr4 SDB for the i860.
        !          1621:    The SVR4 SDB for the i860 insists on having function prologues be
        !          1622:    non-ABI-compliant!
        !          1623: 
        !          1624:    To get fully ABI-compliant prologues, define I860_STRICT_ABI_PROLOGUES
        !          1625:    in the i860svr4.h file.  (By default this is *not* defined).
        !          1626: 
        !          1627:    The differences between the ABI-compliant and non-ABI-compliant prologues
        !          1628:    are that (a) the ABI version seems to require the use of *signed*
        !          1629:    (rather than unsigned) adds and subtracts, and (b) the ordering of
        !          1630:    the various steps (e.g. saving preserved registers, saving the
        !          1631:    return address, setting up the new frame pointer value) is different.
        !          1632: 
        !          1633:    For strict ABI compliance, it seems to be the case that the very last
        !          1634:    thing that is supposed to happen in the prologue is getting the frame
        !          1635:    pointer set to its new value (but only after everything else has
        !          1636:    already been properly setup).  We do that here, but only if the symbol
        !          1637:    I860_STRICT_ABI_PROLOGUES is defined.
        !          1638: */
        !          1639: 
        !          1640: #ifndef STACK_ALIGNMENT
        !          1641: #define STACK_ALIGNMENT        16
        !          1642: #endif
        !          1643: 
        !          1644: extern char call_used_regs[];
        !          1645: extern int leaf_function_p ();
        !          1646: 
        !          1647: char *current_function_original_name;
        !          1648: 
        !          1649: static int must_preserve_r1;
        !          1650: static unsigned must_preserve_bytes;
        !          1651: 
        !          1652: void
        !          1653: function_prologue (asm_file, local_bytes)
        !          1654:      register FILE *asm_file;
        !          1655:      register unsigned local_bytes;
        !          1656: {
        !          1657:   register unsigned frame_lower_bytes;
        !          1658:   register unsigned frame_upper_bytes;
        !          1659:   register unsigned total_fsize;
        !          1660:   register unsigned preserved_reg_bytes = 0;
        !          1661:   register unsigned i;
        !          1662:   register unsigned preserved_so_far = 0;
        !          1663: 
        !          1664:   must_preserve_r1 = (optimize < 2 || ! leaf_function_p ());
        !          1665:   must_preserve_bytes = 4 + (must_preserve_r1 ? 4 : 0);
        !          1666: 
        !          1667:   /* Count registers that need preserving.  Ignore r0.  It never needs
        !          1668:      preserving.  */
        !          1669: 
        !          1670:   for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)
        !          1671:     {
        !          1672:       if (regs_ever_live[i] && ! call_used_regs[i])
        !          1673:         preserved_reg_bytes += 4;
        !          1674:     }
        !          1675: 
        !          1676:   /* Round-up the frame_lower_bytes so that it's a multiple of 16. */
        !          1677: 
        !          1678:   frame_lower_bytes = (local_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT;
        !          1679: 
        !          1680:   /* The upper part of each frame will contain the saved fp,
        !          1681:      the saved r1, and stack slots for all of the other "preserved"
        !          1682:      registers that we find we will need to save & restore. */
        !          1683: 
        !          1684:   frame_upper_bytes = must_preserve_bytes + preserved_reg_bytes;
        !          1685: 
        !          1686:   /* Round-up the frame_upper_bytes so that it's a multiple of 16. */
        !          1687: 
        !          1688:   frame_upper_bytes
        !          1689:     = (frame_upper_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT;
        !          1690: 
        !          1691:   total_fsize = frame_upper_bytes + frame_lower_bytes;
        !          1692: 
        !          1693: #ifndef I860_STRICT_ABI_PROLOGUES
        !          1694: 
        !          1695:   /* There are two kinds of function prologues.
        !          1696:      You use the "small" version if the total frame size is
        !          1697:      small enough so that it can fit into an immediate 16-bit
        !          1698:      value in one instruction.  Otherwise, you use the "large"
        !          1699:      version of the function prologue.  */
        !          1700: 
        !          1701:   if (total_fsize > 0x7fff)
        !          1702:     {
        !          1703:       /* Adjust the stack pointer.  The ABI sez to do this using `adds',
        !          1704:         but the native C compiler on svr4 uses `addu'.  */
        !          1705: 
        !          1706:       fprintf (asm_file, "\taddu -%d,%ssp,%ssp\n",
        !          1707:        frame_upper_bytes, i860_reg_prefix, i860_reg_prefix);
        !          1708: 
        !          1709:       /* Save the old frame pointer.  */
        !          1710: 
        !          1711:       fprintf (asm_file, "\tst.l %sfp,0(%ssp)\n",
        !          1712:        i860_reg_prefix, i860_reg_prefix);
        !          1713: 
        !          1714:       /* Setup the new frame pointer.  The ABI sez to do this after
        !          1715:         preserving registers (using adds), but that's not what the
        !          1716:         native C compiler on svr4 does.  */
        !          1717: 
        !          1718:       fprintf (asm_file, "\taddu 0,%ssp,%sfp\n",
        !          1719:        i860_reg_prefix, i860_reg_prefix);
        !          1720: 
        !          1721:       /* Get the value of frame_lower_bytes into r31.  */
        !          1722: 
        !          1723:       fprintf (asm_file, "\torh %d,%sr0,%sr31\n",
        !          1724:        frame_lower_bytes >> 16, i860_reg_prefix, i860_reg_prefix);
        !          1725:       fprintf (asm_file, "\tor %d,%sr31,%sr31\n",
        !          1726:        frame_lower_bytes & 0xffff, i860_reg_prefix, i860_reg_prefix);
        !          1727: 
        !          1728:       /* Now re-adjust the stack pointer using the value in r31.
        !          1729:         The ABI sez to do this with `subs' but SDB may prefer `subu'.  */
        !          1730: 
        !          1731:       fprintf (asm_file, "\tsubu %ssp,%sr31,%ssp\n",
        !          1732:        i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);
        !          1733: 
        !          1734:       /* Preserve registers.  The ABI sez to do this before setting
        !          1735:         up the new frame pointer, but that's not what the native
        !          1736:         C compiler on svr4 does.  */
        !          1737: 
        !          1738:       for (i = 1; i < 32; i++)
        !          1739:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1740:           fprintf (asm_file, "\tst.l %s%s,%d(%sfp)\n",
        !          1741:            i860_reg_prefix, reg_names[i],
        !          1742:            must_preserve_bytes  + (4 * preserved_so_far++),
        !          1743:            i860_reg_prefix);
        !          1744: 
        !          1745:       for (i = 32; i < 64; i++)
        !          1746:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1747:           fprintf (asm_file, "\tfst.l %s%s,%d(%sfp)\n",
        !          1748:            i860_reg_prefix, reg_names[i],
        !          1749:            must_preserve_bytes + (4 * preserved_so_far++),
        !          1750:            i860_reg_prefix);
        !          1751: 
        !          1752:       /* Save the return address.  */
        !          1753: 
        !          1754:       if (must_preserve_r1)
        !          1755:         fprintf (asm_file, "\tst.l %sr1,4(%sfp)\n",
        !          1756:          i860_reg_prefix, i860_reg_prefix);
        !          1757:     }
        !          1758:   else
        !          1759:     {
        !          1760:       /* Adjust the stack pointer.  The ABI sez to do this using `adds',
        !          1761:         but the native C compiler on svr4 uses `addu'.  */
        !          1762: 
        !          1763:       fprintf (asm_file, "\taddu -%d,%ssp,%ssp\n",
        !          1764:        total_fsize, i860_reg_prefix, i860_reg_prefix);
        !          1765: 
        !          1766:       /* Save the old frame pointer.  */
        !          1767: 
        !          1768:       fprintf (asm_file, "\tst.l %sfp,%d(%ssp)\n",
        !          1769:        i860_reg_prefix, frame_lower_bytes, i860_reg_prefix);
        !          1770: 
        !          1771:       /* Setup the new frame pointer.  The ABI sez to do this after
        !          1772:         preserving registers and after saving the return address,
        !          1773:        (and its saz to do this using adds), but that's not what the
        !          1774:         native C compiler on svr4 does.  */
        !          1775: 
        !          1776:       fprintf (asm_file, "\taddu %d,%ssp,%sfp\n",
        !          1777:        frame_lower_bytes, i860_reg_prefix, i860_reg_prefix);
        !          1778: 
        !          1779:       /* Preserve registers.  The ABI sez to do this before setting
        !          1780:         up the new frame pointer, but that's not what the native
        !          1781:         compiler on svr4 does.  */
        !          1782: 
        !          1783:       for (i = 1; i < 32; i++)
        !          1784:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1785:           fprintf (asm_file, "\tst.l %s%s,%d(%sfp)\n",
        !          1786:            i860_reg_prefix, reg_names[i],
        !          1787:            must_preserve_bytes + (4 * preserved_so_far++),
        !          1788:            i860_reg_prefix);
        !          1789: 
        !          1790:       for (i = 32; i < 64; i++)
        !          1791:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1792:           fprintf (asm_file, "\tfst.l %s%s,%d(%sfp)\n",
        !          1793:            i860_reg_prefix, reg_names[i],
        !          1794:            must_preserve_bytes + (4 * preserved_so_far++),
        !          1795:            i860_reg_prefix);
        !          1796: 
        !          1797:       /* Save the return address.  The ABI sez to do this earlier,
        !          1798:         and also via an offset from %sp, but the native C compiler
        !          1799:         on svr4 does it later (i.e. now) and uses an offset from
        !          1800:         %fp.  */
        !          1801: 
        !          1802:       if (must_preserve_r1)
        !          1803:         fprintf (asm_file, "\tst.l %sr1,4(%sfp)\n",
        !          1804:          i860_reg_prefix, i860_reg_prefix);
        !          1805:     }
        !          1806: 
        !          1807: #else /* defined(I860_STRICT_ABI_PROLOGUES) */
        !          1808: 
        !          1809:   /* There are two kinds of function prologues.
        !          1810:      You use the "small" version if the total frame size is
        !          1811:      small enough so that it can fit into an immediate 16-bit
        !          1812:      value in one instruction.  Otherwise, you use the "large"
        !          1813:      version of the function prologue.  */
        !          1814: 
        !          1815:   if (total_fsize > 0x7fff)
        !          1816:     {
        !          1817:       /* Adjust the stack pointer (thereby allocating a new frame).  */
        !          1818: 
        !          1819:       fprintf (asm_file, "\tadds -%d,%ssp,%ssp\n",
        !          1820:        frame_upper_bytes, i860_reg_prefix, i860_reg_prefix);
        !          1821: 
        !          1822:       /* Save the caller's frame pointer.  */
        !          1823: 
        !          1824:       fprintf (asm_file, "\tst.l %sfp,0(%ssp)\n",
        !          1825:        i860_reg_prefix, i860_reg_prefix);
        !          1826: 
        !          1827:       /* Save return address.  */
        !          1828: 
        !          1829:       if (must_preserve_r1)
        !          1830:         fprintf (asm_file, "\tst.l %sr1,4(%ssp)\n",
        !          1831:          i860_reg_prefix, i860_reg_prefix);
        !          1832: 
        !          1833:       /* Get the value of frame_lower_bytes into r31 for later use.  */
        !          1834: 
        !          1835:       fprintf (asm_file, "\torh %d,%sr0,%sr31\n",
        !          1836:        frame_lower_bytes >> 16, i860_reg_prefix, i860_reg_prefix);
        !          1837:       fprintf (asm_file, "\tor %d,%sr31,%sr31\n",
        !          1838:        frame_lower_bytes & 0xffff, i860_reg_prefix, i860_reg_prefix);
        !          1839: 
        !          1840:       /* Now re-adjust the stack pointer using the value in r31.  */
        !          1841: 
        !          1842:       fprintf (asm_file, "\tsubs %ssp,%sr31,%ssp\n",
        !          1843:        i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);
        !          1844: 
        !          1845:       /* Pre-compute value to be used as the new frame pointer.  */
        !          1846: 
        !          1847:       fprintf (asm_file, "\tadds %ssp,%sr31,%sr31\n",
        !          1848:        i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);
        !          1849: 
        !          1850:       /* Preserve registers.  */
        !          1851: 
        !          1852:       for (i = 1; i < 32; i++)
        !          1853:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1854:           fprintf (asm_file, "\tst.l %s%s,%d(%sr31)\n",
        !          1855:            i860_reg_prefix, reg_names[i],
        !          1856:            must_preserve_bytes + (4 * preserved_so_far++),
        !          1857:            i860_reg_prefix);
        !          1858: 
        !          1859:       for (i = 32; i < 64; i++)
        !          1860:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1861:           fprintf (asm_file, "\tfst.l %s%s,%d(%sr31)\n",
        !          1862:            i860_reg_prefix, reg_names[i],
        !          1863:            must_preserve_bytes + (4 * preserved_so_far++),
        !          1864:            i860_reg_prefix);
        !          1865: 
        !          1866:       /* Actually set the new value of the frame pointer.  */
        !          1867: 
        !          1868:       fprintf (asm_file, "\tmov %sr31,%sfp\n",
        !          1869:        i860_reg_prefix, i860_reg_prefix);
        !          1870:     }
        !          1871:   else
        !          1872:     {
        !          1873:       /* Adjust the stack pointer.  */
        !          1874: 
        !          1875:       fprintf (asm_file, "\tadds -%d,%ssp,%ssp\n",
        !          1876:        total_fsize, i860_reg_prefix, i860_reg_prefix);
        !          1877: 
        !          1878:       /* Save the caller's frame pointer.  */
        !          1879: 
        !          1880:       fprintf (asm_file, "\tst.l %sfp,%d(%ssp)\n",
        !          1881:        i860_reg_prefix, frame_lower_bytes, i860_reg_prefix);
        !          1882: 
        !          1883:       /* Save the return address.  */
        !          1884: 
        !          1885:       if (must_preserve_r1)
        !          1886:         fprintf (asm_file, "\tst.l %sr1,%d(%ssp)\n",
        !          1887:          i860_reg_prefix, frame_lower_bytes + 4, i860_reg_prefix);
        !          1888: 
        !          1889:       /* Preserve registers.  */
        !          1890: 
        !          1891:       for (i = 1; i < 32; i++)
        !          1892:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1893:           fprintf (asm_file, "\tst.l %s%s,%d(%ssp)\n",
        !          1894:            i860_reg_prefix, reg_names[i],
        !          1895:            frame_lower_bytes + must_preserve_bytes + (4 * preserved_so_far++),
        !          1896:            i860_reg_prefix);
        !          1897: 
        !          1898:       for (i = 32; i < 64; i++)
        !          1899:         if (regs_ever_live[i] && ! call_used_regs[i])
        !          1900:           fprintf (asm_file, "\tfst.l %s%s,%d(%ssp)\n",
        !          1901:            i860_reg_prefix, reg_names[i],
        !          1902:            frame_lower_bytes + must_preserve_bytes + (4 * preserved_so_far++),
        !          1903:            i860_reg_prefix);
        !          1904: 
        !          1905:       /* Setup the new frame pointer.  */
        !          1906: 
        !          1907:       fprintf (asm_file, "\tadds %d,%ssp,%sfp\n",
        !          1908:        frame_lower_bytes, i860_reg_prefix, i860_reg_prefix);
        !          1909:     }
        !          1910: #endif /* defined(I860_STRICT_ABI_PROLOGUES) */
        !          1911: 
        !          1912: #ifdef ASM_OUTPUT_PROLOGUE_SUFFIX
        !          1913:   ASM_OUTPUT_PROLOGUE_SUFFIX (asm_file);
        !          1914: #endif /* defined(ASM_OUTPUT_PROLOGUE_SUFFIX) */
        !          1915: }
        !          1916: 
        !          1917: /* This function generates the assembly code for function exit.
        !          1918:    The macro FUNCTION_EPILOGUE in i860.h is defined to call this function.
        !          1919: 
        !          1920:    ASM_FILE is a stdio stream to output the code to.
        !          1921:    SIZE is an int: how many units of temporary storage to allocate.
        !          1922: 
        !          1923:    The function epilogue should not depend on the current stack pointer!
        !          1924:    It should use the frame pointer only.  This is mandatory because
        !          1925:    of alloca; we also take advantage of it to omit stack adjustments
        !          1926:    before returning.
        !          1927: 
        !          1928:    Note that when we go to restore the preserved register values we must
        !          1929:    not try to address their slots by using offsets from the stack pointer.
        !          1930:    That's because the stack pointer may have been moved during the function
        !          1931:    execution due to a call to alloca().  Rather, we must restore all
        !          1932:    preserved registers via offsets from the frame pointer value.
        !          1933: 
        !          1934:    Note also that when the current frame is being "popped" (by adjusting
        !          1935:    the value of the stack pointer) on function exit, we must (for the
        !          1936:    sake of alloca) set the new value of the stack pointer based upon
        !          1937:    the current value of the frame pointer.  We can't just add what we
        !          1938:    believe to be the (static) frame size to the stack pointer because
        !          1939:    if we did that, and alloca() had been called during this function,
        !          1940:    we would end up returning *without* having fully deallocated all of
        !          1941:    the space grabbed by alloca.  If that happened, and a function
        !          1942:    containing one or more alloca() calls was called over and over again,
        !          1943:    then the stack would grow without limit!
        !          1944: 
        !          1945:    Finally note that the epilogues generated here are completely ABI
        !          1946:    compliant.  They go out of their way to insure that the value in
        !          1947:    the frame pointer register is never less than the value in the stack
        !          1948:    pointer register.  It's not clear why this relationship needs to be
        !          1949:    maintained at all times, but maintaining it only costs one extra
        !          1950:    instruction, so what the hell.
        !          1951: */
        !          1952: 
        !          1953: /* This corresponds to a version 4 TDESC structure. Lower numbered
        !          1954:    versions successively omit the last word of the structure. We
        !          1955:    don't try to handle version 5 here. */
        !          1956: 
        !          1957: typedef struct TDESC_flags {
        !          1958:        int version:4;
        !          1959:        int reg_packing:1;
        !          1960:        int callable_block:1;
        !          1961:        int reserved:4;
        !          1962:        int fregs:6;    /* fp regs 2-7 */
        !          1963:        int iregs:16;   /* regs 0-15 */
        !          1964: } TDESC_flags;
        !          1965: 
        !          1966: typedef struct TDESC {
        !          1967:        TDESC_flags flags;
        !          1968:        int integer_reg_offset;         /* same as must_preserve_bytes */
        !          1969:        int floating_point_reg_offset;
        !          1970:        unsigned int positive_frame_size;       /* same as frame_upper_bytes */
        !          1971:        unsigned int negative_frame_size;       /* same as frame_lower_bytes */
        !          1972: } TDESC;
        !          1973: 
        !          1974: void
        !          1975: function_epilogue (asm_file, local_bytes)
        !          1976:      register FILE *asm_file;
        !          1977:      register unsigned local_bytes;
        !          1978: {
        !          1979:   register unsigned frame_upper_bytes;
        !          1980:   register unsigned frame_lower_bytes;
        !          1981:   register unsigned preserved_reg_bytes = 0;
        !          1982:   register unsigned i;
        !          1983:   register unsigned restored_so_far = 0;
        !          1984:   register unsigned int_restored;
        !          1985:   register unsigned mask;
        !          1986:   unsigned intflags=0;
        !          1987:   register TDESC_flags *flags = (TDESC_flags *) &intflags;
        !          1988: 
        !          1989:   flags->version = 4;
        !          1990:   flags->reg_packing = 1;
        !          1991:   flags->iregs = 8;    /* old fp always gets saved */
        !          1992: 
        !          1993:   /* Round-up the frame_lower_bytes so that it's a multiple of 16. */
        !          1994: 
        !          1995:   frame_lower_bytes = (local_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT;
        !          1996: 
        !          1997:   /* Count the number of registers that were preserved in the prologue.
        !          1998:      Ignore r0.  It is never preserved.  */
        !          1999: 
        !          2000:   for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)
        !          2001:     {
        !          2002:       if (regs_ever_live[i] && ! call_used_regs[i])
        !          2003:         preserved_reg_bytes += 4;
        !          2004:     }
        !          2005: 
        !          2006:   /* The upper part of each frame will contain only saved fp,
        !          2007:      the saved r1, and stack slots for all of the other "preserved"
        !          2008:      registers that we find we will need to save & restore. */
        !          2009: 
        !          2010:   frame_upper_bytes = must_preserve_bytes + preserved_reg_bytes;
        !          2011: 
        !          2012:   /* Round-up frame_upper_bytes so that t is a multiple of 16. */
        !          2013: 
        !          2014:   frame_upper_bytes
        !          2015:     = (frame_upper_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT;
        !          2016: 
        !          2017:   /* Restore all of the "preserved" registers that need restoring.  */
        !          2018: 
        !          2019:   mask = 2;
        !          2020: 
        !          2021:   for (i = 1; i < 32; i++, mask<<=1)
        !          2022:     if (regs_ever_live[i] && ! call_used_regs[i]) {
        !          2023:       fprintf (asm_file, "\tld.l %d(%sfp),%s%s\n",
        !          2024:        must_preserve_bytes + (4 * restored_so_far++),
        !          2025:        i860_reg_prefix, i860_reg_prefix, reg_names[i]);
        !          2026:       if (i > 3 && i < 16)
        !          2027:        flags->iregs |= mask;
        !          2028:     }
        !          2029: 
        !          2030:   int_restored = restored_so_far;
        !          2031:   mask = 1;
        !          2032: 
        !          2033:   for (i = 32; i < 64; i++) {
        !          2034:     if (regs_ever_live[i] && ! call_used_regs[i]) {
        !          2035:       fprintf (asm_file, "\tfld.l %d(%sfp),%s%s\n",
        !          2036:        must_preserve_bytes + (4 * restored_so_far++),
        !          2037:        i860_reg_prefix, i860_reg_prefix, reg_names[i]);
        !          2038:       if (i > 33 & i < 40)
        !          2039:        flags->fregs |= mask;
        !          2040:     }
        !          2041:     if (i > 33 && i < 40)
        !          2042:       mask<<=1;
        !          2043:   }
        !          2044: 
        !          2045:   /* Get the value we plan to use to restore the stack pointer into r31.  */
        !          2046: 
        !          2047:   fprintf (asm_file, "\tadds %d,%sfp,%sr31\n",
        !          2048:     frame_upper_bytes, i860_reg_prefix, i860_reg_prefix);
        !          2049: 
        !          2050:   /* Restore the return address and the old frame pointer.  */
        !          2051: 
        !          2052:   if (must_preserve_r1) {
        !          2053:     fprintf (asm_file, "\tld.l 4(%sfp),%sr1\n",
        !          2054:       i860_reg_prefix, i860_reg_prefix);
        !          2055:     flags->iregs |= 2;
        !          2056:   }
        !          2057: 
        !          2058:   fprintf (asm_file, "\tld.l 0(%sfp),%sfp\n",
        !          2059:     i860_reg_prefix, i860_reg_prefix);
        !          2060: 
        !          2061:   /* Return and restore the old stack pointer value.  */
        !          2062: 
        !          2063:   fprintf (asm_file, "\tbri %sr1\n\tmov %sr31,%ssp\n",
        !          2064:     i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);
        !          2065: 
        !          2066: #ifdef OUTPUT_TDESC    /* Output an ABI-compliant TDESC entry */
        !          2067:   if (! frame_lower_bytes) {
        !          2068:     flags->version--;
        !          2069:     if (! frame_upper_bytes) {
        !          2070:       flags->version--;
        !          2071:       if (restored_so_far == int_restored)     /* No FP saves */
        !          2072:        flags->version--;
        !          2073:     }
        !          2074:   }
        !          2075:   assemble_name(asm_file,current_function_original_name);
        !          2076:   fputs(".TDESC:\n", asm_file);
        !          2077:   fprintf(asm_file, "%s 0x%0x\n", ASM_LONG, intflags);
        !          2078:   fprintf(asm_file, "%s %d\n", ASM_LONG,
        !          2079:        int_restored ? must_preserve_bytes : 0);
        !          2080:   if (flags->version > 1) {
        !          2081:     fprintf(asm_file, "%s %d\n", ASM_LONG,
        !          2082:        (restored_so_far == int_restored) ? 0 : must_preserve_bytes +
        !          2083:          (4 * int_restored));
        !          2084:     if (flags->version > 2) {
        !          2085:       fprintf(asm_file, "%s %d\n", ASM_LONG, frame_upper_bytes);
        !          2086:       if (flags->version > 3)
        !          2087:        fprintf(asm_file, "%s %d\n", ASM_LONG, frame_lower_bytes);
        !          2088:     }
        !          2089:   }
        !          2090:   tdesc_section();
        !          2091:   fprintf(asm_file, "%s ", ASM_LONG);
        !          2092:   assemble_name(asm_file, current_function_original_name);
        !          2093:   fprintf(asm_file, "\n%s ", ASM_LONG);
        !          2094:   assemble_name(asm_file, current_function_original_name);
        !          2095:   fputs(".TDESC\n", asm_file);
        !          2096:   text_section();
        !          2097: #endif
        !          2098: }

unix.superglobalmegacorp.com

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