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

1.1     ! root        1: /* Subroutines used for code generation on ROMP.
        !             2:    Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
        !             3:    Contributed by Richard Kenner ([email protected])
        !             4: 
        !             5: This file is part of GNU CC.
        !             6: 
        !             7: GNU CC is free software; you can redistribute it and/or modify
        !             8: it under the terms of the GNU General Public License as published by
        !             9: the Free Software Foundation; either version 2, or (at your option)
        !            10: any later version.
        !            11: 
        !            12: GNU CC is distributed in the hope that it will be useful,
        !            13: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            15: GNU General Public License for more details.
        !            16: 
        !            17: You should have received a copy of the GNU General Public License
        !            18: along with GNU CC; see the file COPYING.  If not, write to
        !            19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            20: 
        !            21: 
        !            22: #include <stdio.h>
        !            23: #include "config.h"
        !            24: #include "rtl.h"
        !            25: #include "regs.h"
        !            26: #include "hard-reg-set.h"
        !            27: #include "real.h"
        !            28: #include "insn-config.h"
        !            29: #include "conditions.h"
        !            30: #include "insn-flags.h"
        !            31: #include "output.h"
        !            32: #include "insn-attr.h"
        !            33: #include "flags.h"
        !            34: #include "recog.h"
        !            35: #include "expr.h"
        !            36: #include "obstack.h"
        !            37: #include "tree.h"
        !            38: 
        !            39: #define min(A,B)       ((A) < (B) ? (A) : (B))
        !            40: #define max(A,B)       ((A) > (B) ? (A) : (B))
        !            41: 
        !            42: static int unsigned_comparisons_p ();
        !            43: static void output_loadsave_fpregs ();
        !            44: static void output_fpops ();
        !            45: static void init_fpops ();
        !            46: 
        !            47: /* Return 1 if the insn using CC0 set by INSN does not contain
        !            48:    any unsigned tests applied to the condition codes.
        !            49: 
        !            50:    Based on `next_insn_tests_no_inequality' in recog.c.  */
        !            51: 
        !            52: int
        !            53: next_insn_tests_no_unsigned (insn)
        !            54:      rtx insn;
        !            55: {
        !            56:   register rtx next = next_cc0_user (insn);
        !            57: 
        !            58:   if (next == 0)
        !            59:     {
        !            60:       if (find_reg_note (insn, REG_UNUSED, cc0_rtx))
        !            61:        return 1;
        !            62:       else
        !            63:        abort ();
        !            64:     }
        !            65: 
        !            66:   return ((GET_CODE (next) == JUMP_INSN
        !            67:           || GET_CODE (next) == INSN
        !            68:           || GET_CODE (next) == CALL_INSN)
        !            69:          && ! unsigned_comparisons_p (PATTERN (next)));
        !            70: }
        !            71: 
        !            72: static int
        !            73: unsigned_comparisons_p (x)
        !            74:      rtx x;
        !            75: {
        !            76:   register char *fmt;
        !            77:   register int len, i;
        !            78:   register enum rtx_code code = GET_CODE (x);
        !            79: 
        !            80:   switch (code)
        !            81:     {
        !            82:     case REG:
        !            83:     case PC:
        !            84:     case CC0:
        !            85:     case CONST_INT:
        !            86:     case CONST_DOUBLE:
        !            87:     case CONST:
        !            88:     case LABEL_REF:
        !            89:     case SYMBOL_REF:
        !            90:       return 0;
        !            91: 
        !            92:     case LTU:
        !            93:     case GTU:
        !            94:     case LEU:
        !            95:     case GEU:
        !            96:       return (XEXP (x, 0) == cc0_rtx || XEXP (x, 1) == cc0_rtx);
        !            97:     }
        !            98: 
        !            99:   len = GET_RTX_LENGTH (code);
        !           100:   fmt = GET_RTX_FORMAT (code);
        !           101: 
        !           102:   for (i = 0; i < len; i++)
        !           103:     {
        !           104:       if (fmt[i] == 'e')
        !           105:        {
        !           106:          if (unsigned_comparisons_p (XEXP (x, i)))
        !           107:            return 1;
        !           108:        }
        !           109:       else if (fmt[i] == 'E')
        !           110:        {
        !           111:          register int j;
        !           112:          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
        !           113:            if (unsigned_comparisons_p (XVECEXP (x, i, j)))
        !           114:              return 1;
        !           115:        }
        !           116:     }
        !           117:            
        !           118:   return 0;
        !           119: }
        !           120: 
        !           121: /* Update the condition code from the insn.  Look mostly at the first
        !           122:    byte of the machine-specific insn description information.
        !           123: 
        !           124:    cc_state.value[12] refer to two possible values that might correspond
        !           125:    to the CC.  We only store register values.  */
        !           126: 
        !           127: update_cc (body, insn)
        !           128:     rtx body;
        !           129:     rtx insn;
        !           130: {
        !           131:   switch (get_attr_cc (insn))
        !           132:     {
        !           133:     case CC_NONE:
        !           134:       /* Insn does not affect the CC at all.  */
        !           135:       break;
        !           136: 
        !           137:     case CC_CHANGE0:
        !           138:       /* Insn doesn't affect the CC but does modify operand[0], known to be
        !           139:         a register.  */
        !           140:       if (cc_status.value1 != 0
        !           141:          && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
        !           142:        cc_status.value1 = 0;
        !           143: 
        !           144:       if (cc_status.value2 != 0
        !           145:          && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
        !           146:        cc_status.value2 = 0;
        !           147: 
        !           148:       break;
        !           149: 
        !           150:     case CC_COPY1TO0:
        !           151:       /* Insn copies operand[1] to operand[0], both registers, but doesn't
        !           152:          affect the CC.  */
        !           153:       if (cc_status.value1 != 0
        !           154:          && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
        !           155:        cc_status.value1 = 0;
        !           156: 
        !           157:       if (cc_status.value2 != 0
        !           158:          && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
        !           159:        cc_status.value2 = 0;
        !           160: 
        !           161:       if (cc_status.value1 != 0
        !           162:          && rtx_equal_p (cc_status.value1, recog_operand[1]))
        !           163:        cc_status.value2 = recog_operand[0];
        !           164: 
        !           165:       if (cc_status.value2 != 0
        !           166:          && rtx_equal_p (cc_status.value2, recog_operand[1]))
        !           167:        cc_status.value1 = recog_operand[0];
        !           168: 
        !           169:       break;
        !           170: 
        !           171:     case CC_CLOBBER:
        !           172:       /* Insn clobbers CC. */
        !           173:       CC_STATUS_INIT;
        !           174:       break;
        !           175: 
        !           176:     case CC_SETS:
        !           177:       /* Insn sets CC to recog_operand[0], but overflow is impossible.  */
        !           178:       CC_STATUS_INIT;
        !           179:       cc_status.flags |= CC_NO_OVERFLOW;
        !           180:       cc_status.value1 = recog_operand[0];
        !           181:       break;
        !           182: 
        !           183:    case CC_COMPARE:
        !           184:       /* Insn is a compare which sets the CC fully.  Update CC_STATUS for this
        !           185:         compare and mark whether the test will be signed or unsigned.  */
        !           186:       {
        !           187:        register rtx p = PATTERN (insn);
        !           188: 
        !           189:        CC_STATUS_INIT;
        !           190: 
        !           191:        if (GET_CODE (p) == PARALLEL)
        !           192:          p = XVECEXP (p, 0, 0);
        !           193:        cc_status.value1 = SET_SRC (p);
        !           194: 
        !           195:        if (GET_CODE (SET_SRC (p)) == REG)
        !           196:          cc_status.flags |= CC_NO_OVERFLOW;
        !           197:        if (! next_insn_tests_no_unsigned (insn))
        !           198:          cc_status.flags |= CC_UNSIGNED;
        !           199:       }
        !           200:       break;
        !           201: 
        !           202:     case CC_TBIT:
        !           203:       /* Insn sets T bit if result is non-zero.  Next insn must be branch. */
        !           204:       CC_STATUS_INIT;
        !           205:       cc_status.flags = CC_IN_TB | CC_NOT_NEGATIVE;
        !           206:       break;
        !           207: 
        !           208:     default:
        !           209:       abort ();
        !           210:    }
        !           211: }
        !           212: 
        !           213: /* Return 1 if a previous compare needs to be re-issued.  This will happen
        !           214:    if two compares tested the same objects, but one was signed and the
        !           215:    other unsigned.  OP is the comparison operation being performed.  */
        !           216: 
        !           217: int
        !           218: restore_compare_p (op)
        !           219:      rtx op;
        !           220: {
        !           221:   enum rtx_code code = GET_CODE (op);
        !           222: 
        !           223:   return (((code == GEU || code == LEU || code == GTU || code == LTU)
        !           224:           && ! (cc_status.flags & CC_UNSIGNED))
        !           225:          || ((code == GE || code == LE || code == GT || code == LT)
        !           226:              && (cc_status.flags & CC_UNSIGNED)));
        !           227: }
        !           228: 
        !           229: /*  Generate the (long) string corresponding to an inline multiply insn.
        !           230:     Note that `r10' does not refer to the register r10, but rather to the
        !           231:     SCR used as the MQ.  */
        !           232: char *
        !           233: output_in_line_mul ()
        !           234: {
        !           235:   static char insns[200];
        !           236:   int i;
        !           237: 
        !           238:   strcpy (insns, "s %0,%0\n");
        !           239:   strcat (insns, "\tmts r10,%1\n");
        !           240:   for (i = 0; i < 16; i++)
        !           241:     strcat (insns, "\tm %0,%2\n");
        !           242:   strcat (insns, "\tmfs r10,%0");
        !           243: 
        !           244:   return insns;
        !           245: }
        !           246: 
        !           247: /* Returns 1 if OP is a memory reference with an offset from a register within
        !           248:    the range specified.  The offset must also be a multiple of the size of the
        !           249:    mode.  */
        !           250: 
        !           251: static int
        !           252: memory_offset_in_range_p (op, mode, low, high)
        !           253:      register rtx op;
        !           254:      enum machine_mode mode;
        !           255:      int low, high;
        !           256: {
        !           257:   int offset = 0;
        !           258: 
        !           259:   if (! memory_operand (op, mode))
        !           260:     return 0;
        !           261: 
        !           262:   while (GET_CODE (op) == SUBREG)
        !           263:     {
        !           264:       offset += SUBREG_WORD (op) * UNITS_PER_WORD;
        !           265: #if BYTES_BIG_ENDIAN
        !           266:       offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op)))
        !           267:                 - min (UNITS_PER_WORD,
        !           268:                        GET_MODE_SIZE (GET_MODE (SUBREG_REG (op)))));
        !           269: #endif
        !           270:       op = SUBREG_REG (op);
        !           271:     }
        !           272: 
        !           273:   /* We must now have either (mem (reg (x)), (mem (plus (reg (x)) (c))),
        !           274:      or a constant pool address.  */
        !           275:   if (GET_CODE (op) != MEM)
        !           276:     abort ();
        !           277: 
        !           278:   /* Now use the actual mode and get the address.  */
        !           279:   mode = GET_MODE (op);
        !           280:   op = XEXP (op, 0);
        !           281:   if (GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op))
        !           282:     offset = get_pool_offset (op) + 12;
        !           283:   else if (GET_CODE (op) == PLUS)
        !           284:     {
        !           285:       if (GET_CODE (XEXP (op, 1)) != CONST_INT
        !           286:          || ! register_operand (XEXP (op, 0), Pmode))
        !           287:        return 0;
        !           288: 
        !           289:       offset += INTVAL (XEXP (op, 1));
        !           290:     }
        !           291: 
        !           292:   else if (! register_operand (op, Pmode))
        !           293:     return 0;
        !           294: 
        !           295:   return (offset >= low && offset <= high
        !           296:          && (offset % GET_MODE_SIZE (mode) == 0));
        !           297: }
        !           298: 
        !           299: /* Return 1 if OP is a valid operand for a memory reference insn that can
        !           300:    only reference indirect through a register.   */
        !           301: 
        !           302: int
        !           303: zero_memory_operand (op, mode)
        !           304:      rtx op;
        !           305:      enum machine_mode mode;
        !           306: {
        !           307:   return memory_offset_in_range_p (op, mode, 0, 0);
        !           308: }
        !           309: 
        !           310: /* Return 1 if OP is a valid operand for a `short' memory reference insn. */
        !           311: 
        !           312: int
        !           313: short_memory_operand (op, mode)
        !           314:      rtx op;
        !           315:      enum machine_mode mode;
        !           316: {
        !           317:   if (mode == VOIDmode)
        !           318:     mode = GET_MODE (op);
        !           319: 
        !           320:   return memory_offset_in_range_p (op, mode, 0,
        !           321:                                   15 * min (UNITS_PER_WORD,
        !           322:                                             GET_MODE_SIZE (mode)));
        !           323: }
        !           324: 
        !           325: /* Returns 1 if OP is a memory reference involving a symbolic constant
        !           326:    that is not in the constant pool. */
        !           327: 
        !           328: int
        !           329: symbolic_memory_operand (op, mode)
        !           330:      register rtx op;
        !           331:      enum machine_mode mode;
        !           332: {
        !           333:   if (! memory_operand (op, mode))
        !           334:     return 0;
        !           335: 
        !           336:   while (GET_CODE (op) == SUBREG)
        !           337:     op = SUBREG_REG (op);
        !           338: 
        !           339:   if (GET_CODE (op) != MEM)
        !           340:     abort ();
        !           341: 
        !           342:   op = XEXP (op, 0);
        !           343:   if (constant_pool_address_operand (op, VOIDmode))
        !           344:     return 0;
        !           345:   else
        !           346:     return romp_symbolic_operand (op, Pmode)
        !           347:       || (GET_CODE (op) == PLUS && register_operand (XEXP (op, 0), Pmode)
        !           348:          && romp_symbolic_operand (XEXP (op, 1), Pmode));
        !           349: }
        !           350: 
        !           351: 
        !           352: /* Returns 1 if OP is a constant pool reference to the current function.  */
        !           353: 
        !           354: int
        !           355: current_function_operand (op, mode)
        !           356:      rtx op;
        !           357:      enum machine_mode mode;
        !           358: {
        !           359:   if (GET_CODE (op) != MEM || GET_CODE (XEXP (op, 0)) != SYMBOL_REF
        !           360:       ||  ! CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
        !           361:     return 0;
        !           362: 
        !           363:   op = get_pool_constant (XEXP (op, 0));
        !           364:   return (GET_CODE (op) == SYMBOL_REF
        !           365:          && ! strcmp (current_function_name, XSTR (op, 0)));
        !           366: }
        !           367: 
        !           368: /* Return non-zero if this function is known to have a null epilogue.  */
        !           369: 
        !           370: int
        !           371: null_epilogue ()
        !           372: {
        !           373:   return (reload_completed
        !           374:          && first_reg_to_save () == 16
        !           375:          && ! romp_pushes_stack ());
        !           376: }
        !           377: 
        !           378: /* Returns 1 if OP is the address of a location in the constant pool.  */
        !           379: 
        !           380: int
        !           381: constant_pool_address_operand (op, mode)
        !           382:      rtx op;
        !           383:      enum machine_mode mode;
        !           384: {
        !           385:   return ((GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op))
        !           386:          || (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == PLUS
        !           387:              && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
        !           388:              && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
        !           389:              && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (op, 0), 0))));
        !           390: }
        !           391: 
        !           392: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
        !           393:    reference and a constant.  */
        !           394: 
        !           395: int
        !           396: romp_symbolic_operand (op, mode)
        !           397:      register rtx op;
        !           398:      enum machine_mode mode;
        !           399: {
        !           400:   switch (GET_CODE (op))
        !           401:     {
        !           402:     case SYMBOL_REF:
        !           403:     case LABEL_REF:
        !           404:       return ! op->integrated;
        !           405: 
        !           406:     case CONST:
        !           407:       op = XEXP (op, 0);
        !           408:       return (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
        !           409:              || GET_CODE (XEXP (op, 0)) == LABEL_REF)
        !           410:             && GET_CODE (XEXP (op, 1)) == CONST_INT;
        !           411: 
        !           412:     default:
        !           413:       return 0;
        !           414:     }
        !           415: }
        !           416: 
        !           417: /* Returns 1 if OP is a valid constant for the ROMP.  */
        !           418: 
        !           419: int
        !           420: constant_operand (op, mode)
        !           421:     register rtx op;
        !           422:     enum machine_mode mode;
        !           423: {
        !           424:   switch (GET_CODE (op))
        !           425:     {
        !           426:     case LABEL_REF:
        !           427:     case SYMBOL_REF:
        !           428:     case PLUS:
        !           429:     case CONST:
        !           430:       return romp_symbolic_operand (op,mode);
        !           431: 
        !           432:     case CONST_INT:
        !           433:       return (unsigned int) (INTVAL (op) + 0x8000) < 0x10000
        !           434:             || (INTVAL (op) & 0xffff) == 0 || (INTVAL (op) & 0xffff0000) == 0;
        !           435: 
        !           436:     default:
        !           437:       return 0;
        !           438:     }
        !           439: }
        !           440: 
        !           441: /* Returns 1 if OP is either a constant integer valid for the ROMP or a
        !           442:    register.  If a register, it must be in the proper mode unless MODE is
        !           443:    VOIDmode.  */
        !           444: 
        !           445: int
        !           446: reg_or_cint_operand (op, mode)
        !           447:       register rtx op;
        !           448:       enum machine_mode mode;
        !           449: {
        !           450:   if (GET_CODE (op) == CONST_INT)
        !           451:     return constant_operand (op, mode);
        !           452: 
        !           453:   return register_operand (op, mode);
        !           454: }
        !           455: 
        !           456: /* Return 1 is the operand is either a register or ANY constant integer.  */
        !           457: 
        !           458: int
        !           459: reg_or_any_cint_operand (op, mode)
        !           460:     register rtx op;
        !           461:     enum machine_mode mode;
        !           462: {
        !           463:      return GET_CODE (op) == CONST_INT || register_operand (op, mode);
        !           464: }
        !           465: 
        !           466: /* Return 1 if the operand is either a register or a valid D-type operand. */
        !           467: 
        !           468: int
        !           469: reg_or_D_operand (op, mode)
        !           470:     register rtx op;
        !           471:     enum machine_mode mode;
        !           472: {
        !           473:   if (GET_CODE (op) == CONST_INT)
        !           474:     return (unsigned) (INTVAL (op) + 0x8000) < 0x10000;
        !           475: 
        !           476:   return register_operand (op, mode);
        !           477: }
        !           478: 
        !           479: /* Return 1 if the operand is either a register or an item that can be
        !           480:    used as the operand of an SI add insn.  */
        !           481: 
        !           482: int
        !           483: reg_or_add_operand (op, mode)
        !           484:     register rtx op;
        !           485:     enum machine_mode mode;
        !           486: {
        !           487:   return reg_or_D_operand (op, mode) || romp_symbolic_operand (op, mode)
        !           488:         || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
        !           489: }
        !           490: 
        !           491: /* Return 1 if the operand is either a register or an item that can be
        !           492:    used as the operand of a ROMP logical AND insn.  */
        !           493: 
        !           494: int
        !           495: reg_or_and_operand (op, mode)
        !           496:     register rtx op;
        !           497:     enum machine_mode mode;
        !           498: {
        !           499:   if (reg_or_cint_operand (op, mode))
        !           500:     return 1;
        !           501: 
        !           502:   if (GET_CODE (op) != CONST_INT)
        !           503:     return 0;
        !           504: 
        !           505:   return (INTVAL (op) & 0xffff) == 0xffff
        !           506:         || (INTVAL (op) & 0xffff0000) == 0xffff0000;
        !           507: }
        !           508: 
        !           509: /* Return 1 if the operand is a register or memory operand.  */
        !           510: 
        !           511: int
        !           512: reg_or_mem_operand (op, mode)
        !           513:      register rtx op;
        !           514:      register enum machine_mode mode;
        !           515: {
        !           516:   return register_operand (op, mode) || memory_operand (op, mode);
        !           517: }
        !           518: 
        !           519: /* Return 1 if the operand is either a register or a memory operand that is
        !           520:    not symbolic.  */
        !           521: 
        !           522: int
        !           523: reg_or_nonsymb_mem_operand (op, mode)
        !           524:     register rtx op;
        !           525:     enum machine_mode mode;
        !           526: {
        !           527:   if (register_operand (op, mode))
        !           528:     return 1;
        !           529: 
        !           530:   if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
        !           531:     return 1;
        !           532: 
        !           533:   return 0;
        !           534: }
        !           535: 
        !           536: /* Return 1 if this operand is valid for the ROMP.  This is any operand except
        !           537:    certain constant integers.  */
        !           538: 
        !           539: int
        !           540: romp_operand (op, mode)
        !           541:     register rtx op;
        !           542:     enum machine_mode mode;
        !           543: {
        !           544:   if (GET_CODE (op) == CONST_INT)
        !           545:     return constant_operand (op, mode);
        !           546: 
        !           547:   return general_operand (op, mode);
        !           548: }
        !           549: 
        !           550: /* Return 1 if the operand is (reg:mode 0).  */
        !           551: 
        !           552: int
        !           553: reg_0_operand (op, mode)
        !           554:      rtx op;
        !           555:      enum machine_mode mode;
        !           556: {
        !           557:   return ((mode == VOIDmode || mode == GET_MODE (op))
        !           558:          && GET_CODE (op) == REG && REGNO (op) == 0);
        !           559: }
        !           560: 
        !           561: /* Return 1 if the operand is (reg:mode 15).  */
        !           562: 
        !           563: int
        !           564: reg_15_operand (op, mode)
        !           565:      rtx op;
        !           566:      enum machine_mode mode;
        !           567: {
        !           568:   return ((mode == VOIDmode || mode == GET_MODE (op))
        !           569:          && GET_CODE (op) == REG && REGNO (op) == 15);
        !           570: }
        !           571: 
        !           572: /* Return 1 if this is a binary floating-point operation.  */
        !           573: 
        !           574: int
        !           575: float_binary (op, mode)
        !           576:     register rtx op;
        !           577:     enum machine_mode mode;
        !           578: {
        !           579:   if (mode != VOIDmode && mode != GET_MODE (op))
        !           580:     return 0;
        !           581: 
        !           582:   if (GET_MODE (op) != SFmode && GET_MODE (op) != DFmode)
        !           583:     return 0;
        !           584: 
        !           585:   switch (GET_CODE (op))
        !           586:     {
        !           587:     case PLUS:
        !           588:     case MINUS:
        !           589:     case MULT:
        !           590:     case DIV:
        !           591:       return GET_MODE (XEXP (op, 0)) == GET_MODE (op)
        !           592:             && GET_MODE (XEXP (op, 1)) == GET_MODE (op);
        !           593: 
        !           594:     default:
        !           595:       return 0;
        !           596:     }
        !           597: }
        !           598: 
        !           599: /* Return 1 if this is a unary floating-point operation.  */
        !           600: 
        !           601: int
        !           602: float_unary (op, mode)
        !           603:     register rtx op;
        !           604:     enum machine_mode mode;
        !           605: {
        !           606:   if (mode != VOIDmode && mode != GET_MODE (op))
        !           607:     return 0;
        !           608: 
        !           609:   if (GET_MODE (op) != SFmode && GET_MODE (op) != DFmode)
        !           610:     return 0;
        !           611: 
        !           612:   return (GET_CODE (op) == NEG || GET_CODE (op) == ABS)
        !           613:         && GET_MODE (XEXP (op, 0)) == GET_MODE (op);
        !           614: }
        !           615: 
        !           616: /* Return 1 if this is a valid floating-point conversion that can be done
        !           617:    as part of an operation by the RT floating-point routines.  */
        !           618: 
        !           619: int
        !           620: float_conversion (op, mode)
        !           621:     register rtx op;
        !           622:     enum machine_mode mode;
        !           623: {
        !           624:   if (mode != VOIDmode && mode != GET_MODE (op))
        !           625:     return 0;
        !           626: 
        !           627:   switch (GET_CODE (op))
        !           628:     {
        !           629:     case FLOAT_TRUNCATE:
        !           630:       return GET_MODE (op) == SFmode && GET_MODE (XEXP (op, 0)) == DFmode;
        !           631: 
        !           632:     case FLOAT_EXTEND:
        !           633:       return GET_MODE (op) == DFmode && GET_MODE (XEXP (op, 0)) == SFmode;
        !           634: 
        !           635:     case FLOAT:
        !           636:       return ((GET_MODE (XEXP (op, 0)) == SImode
        !           637:               || GET_CODE (XEXP (op, 0)) == CONST_INT)
        !           638:              && (GET_MODE (op) == SFmode || GET_MODE (op) == DFmode));
        !           639: 
        !           640:     case FIX:
        !           641:       return ((GET_MODE (op) == SImode
        !           642:               || GET_CODE (XEXP (op, 0)) == CONST_INT)
        !           643:              && (GET_MODE (XEXP (op, 0)) == SFmode
        !           644:                  || GET_MODE (XEXP (op, 0)) == DFmode));
        !           645: 
        !           646:     default:
        !           647:       return 0;
        !           648:     }
        !           649: }
        !           650: 
        !           651: /* Print an operand.  Recognize special options, documented below.  */
        !           652: 
        !           653: void
        !           654: print_operand (file, x, code)
        !           655:     FILE *file;
        !           656:     rtx x;
        !           657:     char code;
        !           658: {
        !           659:   int i;
        !           660: 
        !           661:   switch (code)
        !           662:     {
        !           663:     case 'B':
        !           664:       /* Byte number (const/8) */
        !           665:       if (GET_CODE (x) != CONST_INT)
        !           666:        output_operand_lossage ("invalid %%B value");
        !           667: 
        !           668:       fprintf (file, "%d", INTVAL (x) / 8);
        !           669:       break;
        !           670: 
        !           671:     case 'L':
        !           672:       /* Low order 16 bits of constant.  */
        !           673:       if (GET_CODE (x) != CONST_INT)
        !           674:        output_operand_lossage ("invalid %%L value");
        !           675: 
        !           676:       fprintf (file, "%d", INTVAL (x) & 0xffff);
        !           677:       break;
        !           678: 
        !           679:     case 's':
        !           680:       /* Null or "16" depending on whether the constant is greater than 16. */
        !           681:       if (GET_CODE (x) != CONST_INT)
        !           682:        output_operand_lossage ("invalid %%s value");
        !           683: 
        !           684:       if (INTVAL (x) >= 16)
        !           685:        fprintf (file, "16");
        !           686: 
        !           687:       break;
        !           688: 
        !           689:     case 'S':
        !           690:       /* For shifts: 's' will have given the half.  Just give the amount
        !           691:         within 16.  */
        !           692:       if (GET_CODE (x) != CONST_INT)
        !           693:        output_operand_lossage ("invalid %%S value");
        !           694: 
        !           695:       fprintf (file, "%d", INTVAL (x) & 15);
        !           696:       break;
        !           697: 
        !           698:     case 'b':
        !           699:       /* The number of a single bit set or cleared, mod 16.  Note that the ROMP
        !           700:         numbers bits with the high-order bit 31.  */
        !           701:       if (GET_CODE (x) != CONST_INT)
        !           702:        output_operand_lossage ("invalid %%b value");
        !           703: 
        !           704:       if ((i = exact_log2 (INTVAL (x))) >= 0)
        !           705:        fprintf (file, "%d", (31 - i) % 16);
        !           706:       else if ((i = exact_log2 (~ INTVAL (x))) >= 0)
        !           707:        fprintf (file, "%d", (31 - i) % 16);
        !           708:       else
        !           709:        output_operand_lossage ("invalid %%b value");
        !           710: 
        !           711:       break;
        !           712: 
        !           713:     case 'h':
        !           714:       /* "l" or "u" depending on which half of the constant is zero.  */
        !           715:       if (GET_CODE (x) != CONST_INT)
        !           716:        output_operand_lossage ("invalid %%h value");
        !           717: 
        !           718:       if ((INTVAL (x) & 0xffff0000) == 0)
        !           719:        fprintf (file, "l");
        !           720:       else if ((INTVAL (x) & 0xffff) == 0)
        !           721:        fprintf (file, "u");
        !           722:       else
        !           723:        output_operand_lossage ("invalid %%h value");
        !           724: 
        !           725:       break;
        !           726: 
        !           727:     case 'H':
        !           728:       /* Upper or lower half, depending on which half is zero.  */
        !           729:       if (GET_CODE (x) != CONST_INT)
        !           730:        output_operand_lossage ("invalid %%H value");
        !           731: 
        !           732:       if ((INTVAL (x) & 0xffff0000) == 0)
        !           733:        fprintf (file, "%d", INTVAL (x) & 0xffff);
        !           734:       else if ((INTVAL (x) & 0xffff) == 0)
        !           735:        fprintf (file, "%d", (INTVAL (x) >> 16) & 0xffff);
        !           736:       else
        !           737:        output_operand_lossage ("invalid %%H value");
        !           738: 
        !           739:       break;
        !           740: 
        !           741:     case 'z':
        !           742:       /* Write two characters:
        !           743:                'lo'    if the high order part is all ones
        !           744:                'lz'    if the high order part is all zeros
        !           745:                'uo'    if the low order part is all ones
        !           746:                'uz'    if the low order part is all zeros 
        !           747:        */
        !           748:       if (GET_CODE (x) != CONST_INT)
        !           749:        output_operand_lossage ("invalid %%z value");
        !           750: 
        !           751:       if ((INTVAL (x) & 0xffff0000) == 0)
        !           752:        fprintf (file, "lz");
        !           753:       else if ((INTVAL (x) & 0xffff0000) == 0xffff0000)
        !           754:        fprintf (file, "lo");
        !           755:       else if ((INTVAL (x) & 0xffff) == 0)
        !           756:        fprintf (file, "uz");
        !           757:       else if ((INTVAL (x) & 0xffff) == 0xffff)
        !           758:        fprintf (file, "uo");
        !           759:       else
        !           760:        output_operand_lossage ("invalid %%z value");
        !           761: 
        !           762:       break;
        !           763: 
        !           764:     case 'Z':
        !           765:       /* Upper or lower half, depending on which is non-zero or not
        !           766:         all ones.  Must be consistent with 'z' above.  */
        !           767:       if (GET_CODE (x) != CONST_INT)
        !           768:        output_operand_lossage ("invalid %%Z value");
        !           769: 
        !           770:       if ((INTVAL (x) & 0xffff0000) == 0
        !           771:          || (INTVAL (x) & 0xffff0000) == 0xffff0000)
        !           772:        fprintf (file, "%d", INTVAL (x) & 0xffff);
        !           773:       else if ((INTVAL (x) & 0xffff) == 0 || (INTVAL (x) & 0xffff) == 0xffff)
        !           774:        fprintf (file, "%d", (INTVAL (x) >> 16) & 0xffff);
        !           775:       else
        !           776:        output_operand_lossage ("invalid %%Z value");
        !           777: 
        !           778:       break;
        !           779: 
        !           780:     case 'k':
        !           781:       /* Same as 'z', except the trailing 'o' or 'z' is not written.  */
        !           782:       if (GET_CODE (x) != CONST_INT)
        !           783:        output_operand_lossage ("invalid %%k value");
        !           784: 
        !           785:       if ((INTVAL (x) & 0xffff0000) == 0
        !           786:          || (INTVAL (x) & 0xffff0000) == 0xffff0000)
        !           787:        fprintf (file, "l");
        !           788:       else if ((INTVAL (x) & 0xffff) == 0
        !           789:               || (INTVAL (x) & 0xffff) == 0xffff)
        !           790:        fprintf (file, "u");
        !           791:       else
        !           792:        output_operand_lossage ("invalid %%k value");
        !           793: 
        !           794:       break;
        !           795: 
        !           796:     case 't':
        !           797:       /* Similar to 's', except that we write 'h' or 'u'.  */
        !           798:       if (GET_CODE (x) != CONST_INT)
        !           799:        output_operand_lossage ("invalid %%k value");
        !           800: 
        !           801:       if (INTVAL (x) < 16)
        !           802:        fprintf (file, "u");
        !           803:       else
        !           804:        fprintf (file, "l");
        !           805:       break;
        !           806: 
        !           807:     case 'M':
        !           808:       /* For memory operations, write 's' if the operand is a short
        !           809:         memory operand.  */
        !           810:       if (short_memory_operand (x, VOIDmode))
        !           811:        fprintf (file, "s");
        !           812:       break;
        !           813: 
        !           814:     case 'N':
        !           815:       /* Like 'M', but check for zero memory offset.  */
        !           816:       if (zero_memory_operand (x, VOIDmode))
        !           817:        fprintf (file, "s");
        !           818:       break;
        !           819: 
        !           820:     case 'O':
        !           821:       /* Write low-order part of DImode or DFmode.  Supported for MEM
        !           822:         and REG only.  */
        !           823:       if (GET_CODE (x) == REG)
        !           824:        fprintf (file, "%s", reg_names[REGNO (x) + 1]);
        !           825:       else if (GET_CODE (x) == MEM)
        !           826:        print_operand (file, gen_rtx (MEM, GET_MODE (x),
        !           827:                                      plus_constant (XEXP (x, 0), 4)), 0);
        !           828:       else
        !           829:        abort ();
        !           830:       break;
        !           831: 
        !           832:     case 'C':
        !           833:       /* Offset in constant pool for constant pool address.  */
        !           834:       if (! constant_pool_address_operand (x, VOIDmode))
        !           835:        abort ();
        !           836:       if (GET_CODE (x) == SYMBOL_REF)
        !           837:        fprintf (file, "%d", get_pool_offset (x) + 12);
        !           838:       else 
        !           839:        /* Must be (const (plus (symbol_ref) (const_int))) */
        !           840:        fprintf (file, "%d",
        !           841:                 (get_pool_offset (XEXP (XEXP (x, 0), 0)) + 12
        !           842:                  + INTVAL (XEXP (XEXP (x, 0), 1))));
        !           843:       break;
        !           844: 
        !           845:     case 'j':
        !           846:       /* Branch opcode.  Check for condition in test bit for eq/ne.  */
        !           847:       switch (GET_CODE (x))
        !           848:        {
        !           849:        case EQ:
        !           850:          if (cc_status.flags & CC_IN_TB)
        !           851:            fprintf (file, "ntb");
        !           852:          else
        !           853:            fprintf (file, "eq");
        !           854:          break;
        !           855: 
        !           856:        case NE:
        !           857:          if (cc_status.flags & CC_IN_TB)
        !           858:            fprintf (file, "tb");
        !           859:          else
        !           860:            fprintf (file, "ne");
        !           861:          break;
        !           862: 
        !           863:        case GT:
        !           864:        case GTU:
        !           865:          fprintf (file, "h");
        !           866:          break;
        !           867: 
        !           868:        case LT:
        !           869:        case LTU:
        !           870:          fprintf (file, "l");
        !           871:          break;
        !           872: 
        !           873:        case GE:
        !           874:        case GEU:
        !           875:          fprintf (file, "he");
        !           876:          break;
        !           877: 
        !           878:        case LE:
        !           879:        case LEU:
        !           880:          fprintf (file, "le");
        !           881:          break;
        !           882: 
        !           883:        default:
        !           884:          output_operand_lossage ("invalid %%j value");
        !           885:        }
        !           886:       break;
        !           887: 
        !           888:     case 'J':
        !           889:       /* Reversed branch opcode.  */
        !           890:       switch (GET_CODE (x))
        !           891:        {
        !           892:        case EQ:
        !           893:          if (cc_status.flags & CC_IN_TB)
        !           894:            fprintf (file, "tb");
        !           895:          else
        !           896:            fprintf (file, "ne");
        !           897:          break;
        !           898: 
        !           899:        case NE:
        !           900:          if (cc_status.flags & CC_IN_TB)
        !           901:            fprintf (file, "ntb");
        !           902:          else
        !           903:            fprintf (file, "eq");
        !           904:          break;
        !           905: 
        !           906:        case GT:
        !           907:        case GTU:
        !           908:          fprintf (file, "le");
        !           909:          break;
        !           910: 
        !           911:        case LT:
        !           912:        case LTU:
        !           913:          fprintf (file, "he");
        !           914:          break;
        !           915: 
        !           916:        case GE:
        !           917:        case GEU:
        !           918:          fprintf (file, "l");
        !           919:          break;
        !           920: 
        !           921:        case LE:
        !           922:        case LEU:
        !           923:          fprintf (file, "h");
        !           924:          break;
        !           925: 
        !           926:        default:
        !           927:          output_operand_lossage ("invalid %%j value");
        !           928:        }
        !           929:       break;
        !           930: 
        !           931:     case '.':
        !           932:       /* Output nothing.  Used as delimiter in, e.g., "mc%B1%.3 " */
        !           933:       break;
        !           934: 
        !           935:     case '#':
        !           936:       /* Output 'x' if this insn has a delay slot, else nothing.  */
        !           937:       if (dbr_sequence_length ())
        !           938:        fprintf (file, "x");
        !           939:       break;
        !           940: 
        !           941:     case 0:
        !           942:       if (GET_CODE (x) == REG)
        !           943:        fprintf (file, "%s", reg_names[REGNO (x)]);
        !           944:       else if (GET_CODE (x) == MEM)
        !           945:        {
        !           946:          if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
        !           947:              && current_function_operand (x, Pmode))
        !           948:            fprintf (file, "r14");
        !           949:          else
        !           950:            output_address (XEXP (x, 0));
        !           951:        }
        !           952:       else
        !           953:        output_addr_const (file, x);
        !           954:       break;
        !           955: 
        !           956:     default:
        !           957:       output_operand_lossage ("invalid %%xn code");
        !           958:     }
        !           959: }
        !           960: 
        !           961: /* This page contains routines that are used to determine what the function
        !           962:    prologue and epilogue code will do and write them out.  */
        !           963: 
        !           964: /*  Return the first register that is required to be saved. 16 if none.  */
        !           965: 
        !           966: int
        !           967: first_reg_to_save()
        !           968: {
        !           969:   int first_reg;
        !           970: 
        !           971:   /* Find lowest numbered live register.  */
        !           972:   for (first_reg = 6; first_reg <= 15; first_reg++)
        !           973:     if (regs_ever_live[first_reg])
        !           974:       break;
        !           975: 
        !           976:   /* If we think that we do not have to save r14, see if it will be used
        !           977:      to be sure.  */
        !           978:   if (first_reg > 14 && romp_using_r14 ())
        !           979:     first_reg = 14;
        !           980: 
        !           981:   return first_reg;
        !           982: }
        !           983: 
        !           984: /* Compute the size of the save area in the stack, including the space for
        !           985:    the first four incoming arguments.  */
        !           986: 
        !           987: int
        !           988: romp_sa_size ()
        !           989: {
        !           990:   int size;
        !           991:   int i;
        !           992: 
        !           993:   /* We have the 4 words corresponding to the arguments passed in registers,
        !           994:      4 reserved words, space for static chain, general register save area,
        !           995:      and floating-point save area.  */
        !           996:   size = 4 + 4 + 1 + (16 - first_reg_to_save ());
        !           997: 
        !           998:   /* The documentation says we have to leave 18 words in the save area if
        !           999:      any floating-point registers at all are saved, not the three words
        !          1000:      per register you might otherwise expect.  */
        !          1001:   for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++)
        !          1002:     if (regs_ever_live[i + 17])
        !          1003:       {
        !          1004:        size += 18;
        !          1005:        break;
        !          1006:       }
        !          1007: 
        !          1008:   return size * 4;
        !          1009: }
        !          1010: 
        !          1011: /* Return non-zero if this function makes calls or has fp operations
        !          1012:    (which are really calls).  */
        !          1013: 
        !          1014: int
        !          1015: romp_makes_calls ()
        !          1016: {
        !          1017:   rtx insn;
        !          1018: 
        !          1019:   for (insn = get_insns (); insn; insn = next_insn (insn))
        !          1020:     {
        !          1021:       if (GET_CODE (insn) == CALL_INSN)
        !          1022:        return 1;
        !          1023:       else if (GET_CODE (insn) == INSN)
        !          1024:        {
        !          1025:          rtx body = PATTERN (insn);
        !          1026: 
        !          1027:          if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER
        !          1028:              && GET_CODE (body) != ADDR_VEC
        !          1029:              && GET_CODE (body) != ADDR_DIFF_VEC
        !          1030:              && get_attr_type (insn) == TYPE_FP)
        !          1031:            return 1;
        !          1032:        }
        !          1033:     }
        !          1034: 
        !          1035:   return 0;
        !          1036: }
        !          1037: 
        !          1038: /* Return non-zero if this function will use r14 as a pointer to its
        !          1039:    constant pool.  */
        !          1040: 
        !          1041: int
        !          1042: romp_using_r14 ()
        !          1043: {
        !          1044:   /* If we are debugging, profiling, have a non-empty constant pool, or
        !          1045:      call a function, we need r14.  */
        !          1046:   return (write_symbols != NO_DEBUG || profile_flag || get_pool_size () != 0
        !          1047:          || romp_makes_calls ());
        !          1048: }
        !          1049: 
        !          1050: /* Return non-zero if this function needs to push space on the stack.  */
        !          1051: 
        !          1052: int
        !          1053: romp_pushes_stack ()
        !          1054: {
        !          1055:   /* We need to push the stack if a frame pointer is needed (because the
        !          1056:      stack might be dynamically adjusted), if we are debugging, if the
        !          1057:      total required size is more than 100 bytes, or if we make calls.  */
        !          1058: 
        !          1059:   return (frame_pointer_needed || write_symbols != NO_DEBUG
        !          1060:          || (romp_sa_size () + get_frame_size ()) > 100
        !          1061:          || romp_makes_calls ());
        !          1062: }
        !          1063: 
        !          1064: /* Write function prologue.
        !          1065: 
        !          1066:    We compute the size of the fixed area required as follows:
        !          1067: 
        !          1068:    We always allocate 4 words for incoming arguments, 4 word reserved, 1
        !          1069:    word for static link, as many words as required for general register
        !          1070:    save area, plus 2 words for each FP reg 2-7 that must be saved.  */
        !          1071: 
        !          1072: void
        !          1073: output_prolog (file, size)
        !          1074:      FILE *file;
        !          1075:      int size;
        !          1076: {
        !          1077:   int first_reg;
        !          1078:   int reg_save_offset;
        !          1079:   int fp_save = size + current_function_outgoing_args_size;
        !          1080: 
        !          1081:   init_fpops ();
        !          1082: 
        !          1083:   /* Add in fixed size plus output argument area.  */
        !          1084:   size += romp_sa_size () + current_function_outgoing_args_size;
        !          1085: 
        !          1086:   /* Compute first register to save and perform the save operation if anything
        !          1087:      needs to be saved.  */
        !          1088:   first_reg = first_reg_to_save();
        !          1089:   reg_save_offset = - (4 + 4 + 1 + (16 - first_reg)) * 4;
        !          1090:   if (first_reg == 15)
        !          1091:     fprintf (file, "\tst r15,%d(r1)\n", reg_save_offset);
        !          1092:   else if (first_reg < 16)
        !          1093:     fprintf (file, "\tstm r%d,%d(r1)\n", first_reg, reg_save_offset);
        !          1094: 
        !          1095:   /* Set up pointer to data area if it is needed.  */
        !          1096:   if (romp_using_r14 ())
        !          1097:     fprintf (file, "\tcas r14,r0,r0\n");
        !          1098: 
        !          1099:   /* Set up frame pointer if needed.  */
        !          1100:   if (frame_pointer_needed)
        !          1101:     fprintf (file, "\tcal r13,-%d(r1)\n", romp_sa_size () + 64);
        !          1102: 
        !          1103:   /* Push stack if neeeded.  There are a couple of ways of doing this.  */
        !          1104:   if (romp_pushes_stack ())
        !          1105:     {
        !          1106:       if (size >= 32768)
        !          1107:        {
        !          1108:          if (size >= 65536)
        !          1109:            {
        !          1110:              fprintf (file, "\tcau r0,%d(r0)\n", size >> 16);
        !          1111:              fprintf (file, "\toil r0,r0,%d\n", size & 0xffff);
        !          1112:            }
        !          1113:          else
        !          1114:            fprintf (file, "\tcal16 r0,%d(r0)\n", size);
        !          1115:          fprintf (file, "\ts r1,r0\n");
        !          1116:        }
        !          1117:       else
        !          1118:        fprintf (file, "\tcal r1,-%d(r1)\n", size);
        !          1119:     }
        !          1120: 
        !          1121:   /* Save floating-point registers.  */
        !          1122:   output_loadsave_fpregs (file, USE,
        !          1123:                          plus_constant (stack_pointer_rtx, fp_save));
        !          1124: }
        !          1125: 
        !          1126: /* Output the offset information used by debuggers.
        !          1127:    This is the exactly the total_size value of output_epilog
        !          1128:    which is added to the frame pointer. However the value in the debug
        !          1129:    table is encoded in a space-saving way as follows:
        !          1130: 
        !          1131:    The first byte contains two fields: a 2-bit size field and the first
        !          1132:    6 bits of an offset value. The 2-bit size field is in the high-order
        !          1133:    position and specifies how many subsequent bytes follow after
        !          1134:    this one. An offset value is at most 4-bytes long.
        !          1135: 
        !          1136:    The last 6 bits of the first byte initialize the offset value. In many
        !          1137:    cases where procedures have small local storage, this is enough and, in
        !          1138:    this case, the high-order size field is zero so the byte can (almost) be
        !          1139:    used as is (see below). Thus, the byte value of 0x0d is encodes a offset
        !          1140:    size of 13 words, or 52 bytes.
        !          1141: 
        !          1142:    For procedures with a local space larger than 60 bytes, the 6 bits
        !          1143:    are the high-order 6 bits.  The remaining bytes follow as necessary,
        !          1144:    in Big Endian order.  Thus, the short value of 16907 (= 16384+523)
        !          1145:    encodes an offset of 2092 bytes (523 words).
        !          1146: 
        !          1147:    The total offset value is in words (not bytes), so the final value has to
        !          1148:    be multiplied by 4 before it can be used in address computations by a
        !          1149:    debugger.   */
        !          1150: 
        !          1151: void
        !          1152: output_encoded_offset (file, reg_offset)
        !          1153:      FILE *file;
        !          1154:      unsigned reg_offset;
        !          1155: {
        !          1156:   /* Convert the offset value to 4-byte words rather than bytes. */
        !          1157:   reg_offset = (reg_offset + 3) / 4;
        !          1158: 
        !          1159:   /* Now output 1-4 bytes in encoded form. */
        !          1160:   if (reg_offset < (1 << 6))
        !          1161:     /* Fits into one byte */
        !          1162:     fprintf (file, "\t.byte %d\n", reg_offset);
        !          1163:   else if (reg_offset < (1 << (6 + 8)))
        !          1164:     /* Fits into two bytes */
        !          1165:     fprintf (file, "\t.short %d\n", (1 << (6 + 8)) + reg_offset);
        !          1166:   else if (reg_offset < (1 << (6 + 8 + 8)))
        !          1167:     {
        !          1168:       /* Fits in three bytes */
        !          1169:       fprintf (file, "\t.byte %d\n", (2 << 6) + (reg_offset >> ( 6+ 8)));
        !          1170:       fprintf (file, "\t.short %d\n", reg_offset % (1 << (6 + 8)));
        !          1171:     }
        !          1172:   else
        !          1173:     {
        !          1174:       /* Use 4 bytes.  */
        !          1175:       fprintf (file, "\t.short %d", (3 << (6 + 8)) + (reg_offset >> (6 + 8)));
        !          1176:       fprintf (file, "\t.short %d\n", reg_offset % (1 << (6 + 8)));
        !          1177:     }
        !          1178: }
        !          1179: 
        !          1180: /* Write function epilogue.  */
        !          1181: 
        !          1182: void
        !          1183: output_epilog (file, size)
        !          1184:      FILE *file;
        !          1185:      int size;
        !          1186: {
        !          1187:   int first_reg = first_reg_to_save();
        !          1188:   int pushes_stack = romp_pushes_stack ();
        !          1189:   int reg_save_offset = - ((16 - first_reg) + 1 + 4 + 4) * 4;
        !          1190:   int total_size = (size + romp_sa_size ()
        !          1191:                    + current_function_outgoing_args_size);
        !          1192:   int fp_save = size + current_function_outgoing_args_size;
        !          1193:   int long_frame = total_size >= 32768;
        !          1194:   rtx insn = get_last_insn ();
        !          1195:   int write_code = 1;
        !          1196: 
        !          1197:   int nargs = 0;               /* words of arguments */
        !          1198:   tree argptr;
        !          1199: 
        !          1200:   /* Compute the number of words of arguments.  Since this is just for
        !          1201:      the traceback table, we ignore arguments that don't have a size or
        !          1202:      don't have a fixed size.  */
        !          1203: 
        !          1204:   for (argptr = DECL_ARGUMENTS (current_function_decl);
        !          1205:        argptr; argptr = TREE_CHAIN (argptr))
        !          1206:     {
        !          1207:       int this_size = int_size_in_bytes (TREE_TYPE (argptr));
        !          1208: 
        !          1209:       if (this_size > 0)
        !          1210:        nargs += (this_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
        !          1211:     }
        !          1212:   
        !          1213:   /* If the last insn was a BARRIER, we don't have to write anything except
        !          1214:      the trace table.  */
        !          1215:   if (GET_CODE (insn) == NOTE)
        !          1216:     insn = prev_nonnote_insn (insn);
        !          1217:   if (insn && GET_CODE (insn) == BARRIER)
        !          1218:     write_code = 0;
        !          1219: 
        !          1220:   /* Restore floating-point registers.  */
        !          1221:   if (write_code)
        !          1222:     output_loadsave_fpregs (file, CLOBBER,
        !          1223:                            gen_rtx (PLUS, Pmode, gen_rtx (REG, Pmode, 1),
        !          1224:                                     gen_rtx (CONST_INT, VOIDmode, fp_save)));
        !          1225: 
        !          1226:   /* If we push the stack and do not have size > 32K, adjust the register
        !          1227:      save location to the current position of sp.  Otherwise, if long frame,
        !          1228:      restore sp from fp.  */
        !          1229:   if (pushes_stack && ! long_frame)
        !          1230:     reg_save_offset += total_size;
        !          1231:   else if (long_frame && write_code)
        !          1232:     fprintf (file, "\tcal r1,%d(r13)\n", romp_sa_size () + 64);
        !          1233: 
        !          1234:   /* Restore registers.  */
        !          1235:   if (first_reg == 15 && write_code)
        !          1236:     fprintf (file, "\tl r15,%d(r1)\n", reg_save_offset);
        !          1237:   else if (first_reg < 16 && write_code)
        !          1238:     fprintf (file, "\tlm r%d,%d(r1)\n", first_reg, reg_save_offset);
        !          1239:   if (first_reg == 16) first_reg = 0;
        !          1240: 
        !          1241:   /* Handle popping stack, if needed and write debug table entry.  */
        !          1242:   if (pushes_stack)
        !          1243:     {
        !          1244:       if (write_code)
        !          1245:        {
        !          1246:          if (long_frame)
        !          1247:            fprintf (file, "\tbr r15\n");
        !          1248:          else
        !          1249:            fprintf (file, "\tbrx r15\n\tcal r1,%d(r1)\n", total_size);
        !          1250:        }
        !          1251: 
        !          1252:       /* Table header (0xdf), usual-type stack frame (0x07),
        !          1253:         table header (0xdf), and first register saved.
        !          1254: 
        !          1255:         The final 0x08 means that there is a byte following this one
        !          1256:         describing the number of parameter words and the register used as
        !          1257:         stack pointer.
        !          1258: 
        !          1259:         If GCC passed floating-point parameters in floating-point registers,
        !          1260:         it would be necessary to change the final byte from 0x08 to 0x0c.
        !          1261:         Also an additional entry byte would be need to be emitted to specify
        !          1262:         the first floating-point register.
        !          1263: 
        !          1264:         (See also Section 11 (Trace Tables) in ``IBM/4.3 Linkage Convention,''
        !          1265:         pages IBM/4.3-PSD:5-7 of Volume III of the IBM Academic Operating
        !          1266:         System Manual dated July 1987.)  */
        !          1267: 
        !          1268:       fprintf (file, "\t.long 0x%x\n", 0xdf07df08 + first_reg * 0x10);
        !          1269: 
        !          1270:       if (nargs > 15) nargs = 15;
        !          1271: 
        !          1272:       /* The number of parameter words and the register used as the stack
        !          1273:         pointer (encoded here as r1).
        !          1274: 
        !          1275:         Note: The MetWare Hich C Compiler R2.1y actually gets this wrong;
        !          1276:         it erroneously lists r13 but uses r1 as the stack too. But a bug in
        !          1277:         dbx 1.5 nullifies this mistake---most of the time.
        !          1278:          (Dbx retrieves the value of r13 saved on the stack which is often
        !          1279:         the value of r1 before the call.)  */
        !          1280: 
        !          1281:       fprintf (file, "\t.byte 0x%x1\n", nargs);
        !          1282:       output_encoded_offset (file, total_size);
        !          1283:     }
        !          1284:   else
        !          1285:     {
        !          1286:       if (write_code)
        !          1287:        fprintf (file, "\tbr r15\n");
        !          1288: 
        !          1289:       /* Table header (0xdf), no stack frame (0x02),
        !          1290:         table header (0xdf) and no parameters saved (0x00).
        !          1291: 
        !          1292:         If GCC passed floating-point parameters in floating-point registers,
        !          1293:         it might be necessary to change the final byte from 0x00 to 0x04.
        !          1294:         Also a byte would be needed to specify the first floating-point
        !          1295:         register.  */
        !          1296:       fprintf (file, "\t.long 0xdf02df00\n");
        !          1297:     }
        !          1298: 
        !          1299:   /* Output any pending floating-point operations.  */
        !          1300:   output_fpops (file);
        !          1301: }
        !          1302: 
        !          1303: /* For the ROMP we need to make new SYMBOL_REFs for the actual name of a
        !          1304:    called routine.  To keep them unique we maintain a hash table of all
        !          1305:    that have been created so far.  */
        !          1306: 
        !          1307: struct symref_hashent {
        !          1308:   rtx symref;                  /* Created SYMBOL_REF rtx.  */
        !          1309:   struct symref_hashent *next; /* Next with same hash code.  */
        !          1310: };
        !          1311: 
        !          1312: #define SYMHASHSIZE 151
        !          1313: #define HASHBITS 65535
        !          1314: 
        !          1315: /* Define the hash table itself.  */
        !          1316: 
        !          1317: static struct symref_hashent *symref_hash_table[SYMHASHSIZE];
        !          1318: 
        !          1319: /* Given a name (allocatable in temporary storage), return a SYMBOL_REF
        !          1320:    for the name.  The rtx is allocated from the current rtl_obstack, while
        !          1321:    the name string is allocated from the permanent obstack.  */
        !          1322: rtx
        !          1323: get_symref (name)
        !          1324:      register char *name;
        !          1325: {
        !          1326:   extern struct obstack permanent_obstack;
        !          1327:   register char *sp = name;
        !          1328:   unsigned int hash = 0;
        !          1329:   struct symref_hashent *p, **last_p;
        !          1330: 
        !          1331:   /* Compute the hash code for the string.  */
        !          1332:   while (*sp)
        !          1333:     hash = (hash << 4) + *sp++;
        !          1334: 
        !          1335:   /* Search for a matching entry in the hash table, keeping track of the
        !          1336:      insertion location as we do so.  */
        !          1337:   hash = (hash & HASHBITS) % SYMHASHSIZE;
        !          1338:   for (last_p = &symref_hash_table[hash], p = *last_p;
        !          1339:        p; last_p = &p->next, p = *last_p)
        !          1340:     if (strcmp (name, XSTR (p->symref, 0)) == 0)
        !          1341:       break;
        !          1342: 
        !          1343:   /* If couldn't find matching SYMBOL_REF, make a new one.  */
        !          1344:   if (p == 0)
        !          1345:     {
        !          1346:       /* Ensure SYMBOL_REF will stay around.  */
        !          1347:       end_temporary_allocation ();
        !          1348:       p = *last_p = (struct symref_hashent *)
        !          1349:                        permalloc (sizeof (struct symref_hashent));
        !          1350:       p->symref = gen_rtx (SYMBOL_REF, Pmode,
        !          1351:                           obstack_copy0 (&permanent_obstack,
        !          1352:                                          name, strlen (name)));
        !          1353:       p->next = 0;
        !          1354:       resume_temporary_allocation ();
        !          1355:     }
        !          1356: 
        !          1357:   return p->symref;
        !          1358: }
        !          1359: 
        !          1360: /* Validate the precision of a floating-point operation.
        !          1361: 
        !          1362:    We merge conversions from integers and between floating-point modes into
        !          1363:    the insn.  However, this must not effect the desired precision of the
        !          1364:    insn.  The RT floating-point system uses the widest of the operand modes.
        !          1365:    If this should be a double-precision insn, ensure that one operand
        !          1366:    passed to the floating-point processor has double mode.
        !          1367: 
        !          1368:    Note that since we don't check anything if the mode is single precision,
        !          1369:    it, strictly speaking, isn't necessary to call this for those insns.
        !          1370:    However, we do so in case something else needs to be checked in the
        !          1371:    future.
        !          1372: 
        !          1373:    This routine returns 1 if the operation is OK.  */
        !          1374: 
        !          1375: int
        !          1376: check_precision (opmode, op1, op2)
        !          1377:      enum machine_mode opmode;
        !          1378:      rtx op1, op2;
        !          1379: {
        !          1380:   if (opmode == SFmode)
        !          1381:     return 1;
        !          1382: 
        !          1383:   /* If operand is not a conversion from an integer mode or an extension from
        !          1384:      single-precision, it must be a double-precision value.  */
        !          1385:   if (GET_CODE (op1) != FLOAT && GET_CODE (op1) != FLOAT_EXTEND)
        !          1386:     return 1;
        !          1387: 
        !          1388:   if (op2 && GET_CODE (op2) != FLOAT && GET_CODE (op2) != FLOAT_EXTEND)
        !          1389:     return 1;
        !          1390: 
        !          1391:   return 0;
        !          1392: }
        !          1393: 
        !          1394: /* Floating-point on the RT is done by creating an operation block in the data
        !          1395:    area that describes the operation.  If two floating-point operations are the
        !          1396:    same in a single function, they can use the same block.
        !          1397: 
        !          1398:    These routines are responsible for managing these blocks.  */
        !          1399: 
        !          1400: /* Structure to describe a floating-point operation.  */
        !          1401: 
        !          1402: struct fp_op {
        !          1403:   struct fp_op *next_same_hash;                /* Next op with same hash code. */
        !          1404:   struct fp_op *next_in_mem;           /* Next op in memory. */
        !          1405:   int mem_offset;                      /* Offset from data area.  */
        !          1406:   short size;                          /* Size of block in bytes.  */
        !          1407:   short noperands;                     /* Number of operands in block.  */
        !          1408:   rtx ops[3];                          /* RTL for operands. */
        !          1409:   enum rtx_code opcode;                        /* Operation being performed.  */
        !          1410: };
        !          1411: 
        !          1412: /* Size of hash table.  */
        !          1413: #define FP_HASH_SIZE 101
        !          1414: 
        !          1415: /* Hash table of floating-point operation blocks.  */
        !          1416: static struct fp_op *fp_hash_table[FP_HASH_SIZE];
        !          1417: 
        !          1418: /* First floating-point block in data area.  */
        !          1419: static struct fp_op *first_fpop;
        !          1420: 
        !          1421: /* Last block in data area so far.  */
        !          1422: static struct fp_op *last_fpop_in_mem;
        !          1423: 
        !          1424: /* Subroutine number in file, to get unique "LF" labels.  */
        !          1425: static int subr_number = 0;
        !          1426: 
        !          1427: /* Current word offset in data area (includes header and any constant pool). */
        !          1428: int data_offset;
        !          1429: 
        !          1430: /* Compute hash code for an RTX used in floating-point.  */
        !          1431: 
        !          1432: static unsigned int
        !          1433: hash_rtx (x)
        !          1434:      register rtx x;
        !          1435: {
        !          1436:   register unsigned int hash = (((int) GET_CODE (x) << 10)
        !          1437:                                + ((int) GET_MODE (x) << 20));
        !          1438:   register int i;
        !          1439:   register char *fmt = GET_RTX_FORMAT (GET_CODE (x));
        !          1440: 
        !          1441:   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
        !          1442:     if (fmt[i] == 'e')
        !          1443:       hash += hash_rtx (XEXP (x, i));
        !          1444:     else if (fmt[i] == 'u')
        !          1445:       hash += (int) XEXP (x, i);
        !          1446:     else if (fmt[i] == 'i')
        !          1447:       hash += XINT (x, i);
        !          1448:     else if (fmt[i] == 's')
        !          1449:       hash += (int) XSTR (x, i);
        !          1450: 
        !          1451:   return hash;
        !          1452: }
        !          1453: 
        !          1454: /* Given an operation code and up to three operands, return a character string
        !          1455:    corresponding to the code to emit to branch to a floating-point operation
        !          1456:    block.  INSN is provided to see if the delay slot has been filled or not.
        !          1457: 
        !          1458:    A new floating-point operation block is created if this operation has not
        !          1459:    been seen before.  */
        !          1460: 
        !          1461: char *
        !          1462: output_fpop (code, op0, op1, op2, insn)
        !          1463:      enum rtx_code code;
        !          1464:      rtx op0, op1, op2;
        !          1465:      rtx insn;
        !          1466: {
        !          1467:   static char outbuf[40];
        !          1468:   unsigned int hash, hash0, hash1, hash2;
        !          1469:   int size, i;
        !          1470:   register struct fp_op *fpop, *last_fpop;
        !          1471:   int dyadic = (op2 != 0);
        !          1472:   enum machine_mode opmode;
        !          1473:   int noperands;
        !          1474:   rtx tem;
        !          1475:   unsigned int tem_hash;
        !          1476:   int fr0_avail = 0;
        !          1477: 
        !          1478:   /* Compute hash code for each operand.  If the operation is commutative,
        !          1479:      put the one with the smaller hash code first.  This will make us see
        !          1480:      more operations as identical.  */
        !          1481:   hash0 = op0 ? hash_rtx (op0) : 0;
        !          1482:   hash1 = op1 ? hash_rtx (op1) : 0;
        !          1483:   hash2 = op2 ? hash_rtx (op2) : 0;
        !          1484: 
        !          1485:   if (hash0 > hash1 && code == EQ)
        !          1486:     {
        !          1487:       tem = op0; op0 = op1; op1 = tem;
        !          1488:       tem_hash = hash0; hash0 = hash1; hash1 = tem_hash;
        !          1489:     }
        !          1490:   else if (hash1 > hash2 && (code == PLUS || code == MULT))
        !          1491:     {
        !          1492:       tem = op1; op1 = op2; op2 = tem;
        !          1493:       tem_hash = hash1; hash1 = hash2; hash2 = tem_hash;
        !          1494:     }
        !          1495: 
        !          1496:   /* If operation is commutative and the first and third operands are equal,
        !          1497:      swap the second and third operands.  Note that we must consider two
        !          1498:      operands equal if they are the same register even if different modes.  */
        !          1499:   if (op2 && (code == PLUS || code == MULT)
        !          1500:       && (rtx_equal_p (op0, op2)
        !          1501:          || (GET_CODE (op0) == REG && GET_CODE (op2) == REG
        !          1502:              && REGNO (op0) == REGNO (op2))))
        !          1503:     {
        !          1504:       tem = op1; op1 = op2; op2 = tem;
        !          1505:       tem_hash = hash1; hash1 = hash2; hash2 = tem_hash;
        !          1506:     }
        !          1507: 
        !          1508:   /* If the first and second operands are the same, merge them.  Don't do this
        !          1509:      for SFmode or SImode in general registers because this triggers a bug in
        !          1510:      the RT fp code.  */
        !          1511:   if (op1 && rtx_equal_p (op0, op1)
        !          1512:       && code != EQ && code != GE && code != SET
        !          1513:       && ((GET_MODE (op1) != SFmode && GET_MODE (op1) != SImode)
        !          1514:          || GET_CODE (op0) != REG || FP_REGNO_P (REGNO (op0))))
        !          1515:     {
        !          1516:       op1 = op2;
        !          1517:       op2 = 0;
        !          1518:     }
        !          1519: 
        !          1520:   noperands = 1 + (op1 != 0) + (op2 != 0);
        !          1521: 
        !          1522:   /* Compute hash code for entire expression and see if operation block
        !          1523:      already exists.  */
        !          1524:   hash = ((int) code << 13) + (hash0 << 2) + (hash1 << 1) + hash2;
        !          1525: 
        !          1526:   hash %= FP_HASH_SIZE;
        !          1527:   for (fpop = fp_hash_table[hash], last_fpop = 0;
        !          1528:        fpop;
        !          1529:        last_fpop = fpop, fpop = fpop->next_same_hash)
        !          1530:     if (fpop->opcode == code && noperands == fpop->noperands
        !          1531:        && (op0 == 0 || rtx_equal_p (op0, fpop->ops[0]))
        !          1532:        && (op1 == 0 || rtx_equal_p (op1, fpop->ops[1]))
        !          1533:        && (op2 == 0 || rtx_equal_p (op2, fpop->ops[2])))
        !          1534:       goto win;
        !          1535: 
        !          1536:   /* We have never seen this operation before.  */
        !          1537:   fpop = (struct fp_op *) oballoc (sizeof (struct fp_op));
        !          1538:   fpop->mem_offset = data_offset;
        !          1539:   fpop->opcode = code;
        !          1540:   fpop->noperands = noperands;
        !          1541:   fpop->ops[0] = op0;
        !          1542:   fpop->ops[1] = op1;
        !          1543:   fpop->ops[2] = op2;
        !          1544: 
        !          1545:   /* Compute the size using the rules in Appendix A of the RT Linkage
        !          1546:      Convention (4.3/RT-PSD:5) manual.  These rules are a bit ambiguous,
        !          1547:      but if we guess wrong, it will effect only efficiency, not correctness. */
        !          1548: 
        !          1549:   /* Size = 24 + 32 for each non-fp (or fr7) */
        !          1550:   size = 24;
        !          1551:   if (op0 && (GET_CODE (op0) != REG
        !          1552:              || ! FP_REGNO_P (REGNO (op0)) || REGNO (op0) == 23))
        !          1553:     size += 32;
        !          1554: 
        !          1555:   if (op1 && (GET_CODE (op1) != REG
        !          1556:              || ! FP_REGNO_P (REGNO (op1)) || REGNO (op1) == 23))
        !          1557:     size += 32;
        !          1558: 
        !          1559:   if (op2 && (GET_CODE (op2) != REG
        !          1560:              || ! FP_REGNO_P (REGNO (op2)) || REGNO (op2) == 23))
        !          1561:     size += 32;
        !          1562: 
        !          1563:   /* Size + 12 for each conversion.  First get operation mode.  */
        !          1564:   if ((op0 && GET_MODE (op0) == DFmode)
        !          1565:       || (op1 && GET_MODE (op1) == DFmode)
        !          1566:       || (op2 && GET_MODE (op2) == DFmode))
        !          1567:     opmode = DFmode;
        !          1568:   else
        !          1569:     opmode = SFmode;
        !          1570: 
        !          1571:   if (op0 && GET_MODE (op0) != opmode)
        !          1572:     size += 12;
        !          1573:   if (op1 && GET_MODE (op1) != opmode)
        !          1574:     size += 12;
        !          1575:   if (op2 && GET_MODE (op2) != opmode)
        !          1576:     size += 12;
        !          1577: 
        !          1578:   /* 12 more if first and third operand types not the same. */
        !          1579:   if (op2 && GET_MODE (op0) != GET_MODE (op2))
        !          1580:     size += 12;
        !          1581: 
        !          1582:   /* CMP and CMPT need additional.  Also, compute size of save/restore here. */
        !          1583:   if (code == EQ)
        !          1584:     size += 32;
        !          1585:   else if (code == GE)
        !          1586:     size += 64;
        !          1587:   else if (code == USE || code == CLOBBER)
        !          1588:     {
        !          1589:       /* 34 + 24 for each additional register plus 8 if fr7 saved.  (We
        !          1590:          call it 36 because we need to keep the block length a multiple
        !          1591:         of four.  */
        !          1592:       size = 36 - 24;
        !          1593:       for (i = 0; i <= 7; i++)
        !          1594:        if (INTVAL (op0) & (1 << (7-i)))
        !          1595:          size += 24 + 8 * (i == 7);
        !          1596:     }
        !          1597: 
        !          1598:   /* We provide no general-purpose scratch registers.  */
        !          1599:   size +=16;
        !          1600: 
        !          1601:   /* No floating-point scratch registers are provided.  Compute extra
        !          1602:      length due to this.  This logic is that shown in the referenced
        !          1603:      appendix.  */
        !          1604: 
        !          1605:   i = 0;
        !          1606:   if (op0 && GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)))
        !          1607:     i++;
        !          1608:   if (op1 && GET_CODE (op1) == REG && FP_REGNO_P (REGNO (op1)))
        !          1609:     i++;
        !          1610:   if (op2 && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
        !          1611:     i++;
        !          1612: 
        !          1613:   if ((op0 == 0 || GET_CODE (op0) != REG || REGNO(op0) != 17)
        !          1614:       && (op1 == 0 || GET_CODE (op1) != REG || REGNO(op1) != 17)
        !          1615:       && (op2 == 0 || GET_CODE (op2) != REG || REGNO(op2) != 17))
        !          1616:     fr0_avail = 1;
        !          1617: 
        !          1618:   if (dyadic)
        !          1619:     {
        !          1620:       if (i == 0)
        !          1621:        size += fr0_avail ? 64 : 112;
        !          1622:       else if (fpop->noperands == 2 && i == 1)
        !          1623:        size += fr0_avail ? 0 : 64;
        !          1624:       else if (fpop->noperands == 3)
        !          1625:        {
        !          1626:          if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))
        !          1627:              && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
        !          1628:            {
        !          1629:              if (REGNO (op0) == REGNO (op2))
        !          1630: #if 1
        !          1631:                /* This triggers a bug on the RT. */
        !          1632:                abort ();
        !          1633: #else
        !          1634:                size += fr0_avail ? 0 : 64;
        !          1635: #endif
        !          1636:            }
        !          1637:          else
        !          1638:            {
        !          1639:              i = 0;
        !          1640:              if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)))
        !          1641:                i++;
        !          1642:              if (GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
        !          1643:                i++;
        !          1644:              if (i == 0)
        !          1645:                size += fr0_avail ? 64 : 112;
        !          1646:              else if (i == 1)
        !          1647:                size += fr0_avail ? 0 : 64;
        !          1648:            }
        !          1649:        }
        !          1650:     }
        !          1651:   else if (code != USE && code != CLOBBER
        !          1652:           && (GET_CODE (op0) != REG || ! FP_REGNO_P (REGNO (op0))))
        !          1653:     size += 64;
        !          1654:     
        !          1655:   if (! TARGET_FULL_FP_BLOCKS)
        !          1656:     {
        !          1657:       /* If we are not to pad the blocks, just compute its actual length.  */
        !          1658:       size = 12;       /* Header + opcode */
        !          1659:       if (code == USE || code == CLOBBER)
        !          1660:         size += 2;
        !          1661:       else
        !          1662:         {
        !          1663:          if (op0) size += 2;
        !          1664:          if (op1) size += 2;
        !          1665:          if (op2) size += 2;
        !          1666:        }
        !          1667: 
        !          1668:       /* If in the middle of a word, round.  */
        !          1669:       if (size % UNITS_PER_WORD)
        !          1670:        size += 2;
        !          1671:        
        !          1672:       /* Handle any immediates.  */
        !          1673:       if (code != USE && code != CLOBBER && op0 && GET_CODE (op0) != REG)
        !          1674:         size += 4;
        !          1675:       if (op1 && GET_CODE (op1) != REG)
        !          1676:         size += 4;
        !          1677:       if (op2 && GET_CODE (op2) != REG)
        !          1678:         size += 4;
        !          1679: 
        !          1680:       if (code != USE && code != CLOBBER && 
        !          1681:          op0 && GET_CODE (op0) == CONST_DOUBLE && GET_MODE (op0) == DFmode)
        !          1682:         size += 4;
        !          1683:       if (op1 && GET_CODE (op1) == CONST_DOUBLE && GET_MODE (op1) == DFmode)
        !          1684:         size += 4;
        !          1685:       if (op2 && GET_CODE (op2) == CONST_DOUBLE && GET_MODE (op2) == DFmode)
        !          1686:         size += 4;
        !          1687:     }
        !          1688: 
        !          1689:   /* Done with size computation!  Chain this in. */
        !          1690:   fpop->size = size;
        !          1691:   data_offset += size / UNITS_PER_WORD;
        !          1692:   fpop->next_in_mem = 0;
        !          1693:   fpop->next_same_hash = 0;
        !          1694: 
        !          1695:   if (last_fpop_in_mem)
        !          1696:     last_fpop_in_mem->next_in_mem = fpop;
        !          1697:   else
        !          1698:     first_fpop = fpop;
        !          1699:   last_fpop_in_mem = fpop;
        !          1700: 
        !          1701:   if (last_fpop)
        !          1702:     last_fpop->next_same_hash = fpop;
        !          1703:   else
        !          1704:     fp_hash_table[hash] = fpop;
        !          1705: 
        !          1706: win:
        !          1707:   /* FPOP describes the operation to be performed.  Return a string to branch
        !          1708:      to it.  */
        !          1709:   if (fpop->mem_offset < 32768 / UNITS_PER_WORD)
        !          1710:     sprintf (outbuf, "cal r15,%d(r14)\n\tbalr%s r15,r15",
        !          1711:             fpop->mem_offset * UNITS_PER_WORD,
        !          1712:             dbr_sequence_length () ? "x" : "");
        !          1713:   else
        !          1714:     sprintf (outbuf, "get r15,$L%dF%d\n\tbalr%s r15,r15",
        !          1715:             subr_number, fpop->mem_offset * UNITS_PER_WORD,
        !          1716:             dbr_sequence_length () ? "x" : "");
        !          1717:   return outbuf;
        !          1718: }
        !          1719: 
        !          1720: /* If necessary, output a floating-point operation to save or restore all
        !          1721:    floating-point registers.
        !          1722: 
        !          1723:    file is the file to write the operation to, CODE is USE for save, CLOBBER
        !          1724:    for restore, and ADDR is the address of the same area, as RTL.  */
        !          1725: 
        !          1726: static void
        !          1727: output_loadsave_fpregs (file, code, addr)
        !          1728:      FILE *file;
        !          1729:      enum rtx_code code;
        !          1730:      rtx addr;
        !          1731: {
        !          1732:   register int i;
        !          1733:   register int mask = 0;
        !          1734: 
        !          1735:   for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++)
        !          1736:     if (regs_ever_live[i + 17])
        !          1737:       mask |= 1 << (7 - i);
        !          1738: 
        !          1739:   if (mask)
        !          1740:     fprintf (file, "\t%s\n",
        !          1741:             output_fpop (code, gen_rtx (CONST_INT, VOIDmode, mask),
        !          1742:                                gen_rtx (MEM, Pmode, addr),
        !          1743:                                0, const0_rtx));
        !          1744: 
        !          1745: }
        !          1746: 
        !          1747: /* Output any floating-point operations at the end of the routine.  */
        !          1748: 
        !          1749: static void
        !          1750: output_fpops (file)
        !          1751:      FILE *file;
        !          1752: {
        !          1753:   register struct fp_op *fpop;
        !          1754:   register int size_so_far;
        !          1755:   register int i;
        !          1756:   rtx immed[3];
        !          1757: 
        !          1758:   if (first_fpop == 0)
        !          1759:     return;
        !          1760: 
        !          1761:   data_section ();
        !          1762: 
        !          1763:   ASM_OUTPUT_ALIGN (file, 2);
        !          1764: 
        !          1765:   for (fpop = first_fpop; fpop; fpop = fpop->next_in_mem)
        !          1766:     {
        !          1767:       if (fpop->mem_offset < 32768 / UNITS_PER_WORD)
        !          1768:        fprintf (file, "# data area offset = %d\n",
        !          1769:                 fpop->mem_offset * UNITS_PER_WORD);
        !          1770:       else
        !          1771:        fprintf (file, "L%dF%d:\n",
        !          1772:                 subr_number, fpop->mem_offset * UNITS_PER_WORD);
        !          1773: 
        !          1774:       fprintf (file, "\tcas r0,r15,r0\n");
        !          1775:       fprintf (file, "\t.long FPGLUE\n");
        !          1776:       switch (fpop->opcode)
        !          1777:        {
        !          1778:        case USE:
        !          1779:          fprintf (file, "\t.byte 0x1d\t# STOREM\n");
        !          1780:          break;
        !          1781:        case CLOBBER:
        !          1782:          fprintf (file, "\t.byte 0x0f\t# LOADM\n");
        !          1783:          break;
        !          1784:        case ABS:
        !          1785:          fprintf (file, "\t.byte 0x00\t# ABS\n");
        !          1786:          break;
        !          1787:        case PLUS:
        !          1788:          fprintf (file, "\t.byte 0x02\t# ADD\n");
        !          1789:          break;
        !          1790:        case EQ:
        !          1791:          fprintf (file, "\t.byte 0x07\t# CMP\n");
        !          1792:          break;
        !          1793:        case GE:
        !          1794:          fprintf (file, "\t.byte 0x08\t# CMPT\n");
        !          1795:          break;
        !          1796:        case DIV:
        !          1797:          fprintf (file, "\t.byte 0x0c\t# DIV\n");
        !          1798:          break;
        !          1799:        case SET:
        !          1800:          fprintf (file, "\t.byte 0x14\t# MOVE\n");
        !          1801:          break;
        !          1802:        case MULT:
        !          1803:          fprintf (file, "\t.byte 0x15\t# MUL\n");
        !          1804:          break;
        !          1805:        case NEG:
        !          1806:          fprintf (file, "\t.byte 0x16\t# NEG\n");
        !          1807:          break;
        !          1808:        case SQRT:
        !          1809:          fprintf (file, "\t.byte 0x1c\t# SQRT\n");
        !          1810:          break;
        !          1811:        case MINUS:
        !          1812:          fprintf (file, "\t.byte 0x1e\t# SUB\n");
        !          1813:          break;
        !          1814:        default:
        !          1815:          abort ();
        !          1816:        }
        !          1817: 
        !          1818:       fprintf (file, "\t.byte %d\n", fpop->noperands);
        !          1819:       fprintf (file, "\t.short 0x8001\n");
        !          1820:       
        !          1821:       if ((fpop->ops[0] == 0
        !          1822:           || GET_CODE (fpop->ops[0]) != REG || REGNO(fpop->ops[0]) != 17)
        !          1823:          && (fpop->ops[1] == 0 || GET_CODE (fpop->ops[1]) != REG
        !          1824:              || REGNO(fpop->ops[1]) != 17)
        !          1825:          && (fpop->ops[2] == 0 || GET_CODE (fpop->ops[2]) != REG
        !          1826:              || REGNO(fpop->ops[2]) != 17))
        !          1827:        fprintf (file, "\t.byte %d, 0x80\n", fpop->size);
        !          1828:       else
        !          1829:        fprintf (file, "\t.byte %d, 0\n", fpop->size);
        !          1830:       size_so_far = 12;
        !          1831:       for (i = 0; i < fpop->noperands; i++)
        !          1832:        {
        !          1833:          register int type;
        !          1834:          register int opbyte;
        !          1835:          register char *desc0;
        !          1836:          char desc1[50];
        !          1837: 
        !          1838:          immed[i] = 0;
        !          1839:          switch (GET_MODE (fpop->ops[i]))
        !          1840:            {
        !          1841:            case SImode:
        !          1842:            case VOIDmode:
        !          1843:              desc0 = "int";
        !          1844:              type = 0;
        !          1845:              break;
        !          1846:            case SFmode:
        !          1847:              desc0 = "float";
        !          1848:              type = 2;
        !          1849:              break;
        !          1850:            case DFmode:
        !          1851:              desc0 = "double";
        !          1852:              type = 3;
        !          1853:              break;
        !          1854:            default:
        !          1855:              abort ();
        !          1856:            }
        !          1857: 
        !          1858:          switch (GET_CODE (fpop->ops[i]))
        !          1859:            {
        !          1860:            case REG:
        !          1861:              strcpy(desc1, reg_names[REGNO (fpop->ops[i])]);
        !          1862:              if (FP_REGNO_P (REGNO (fpop->ops[i])))
        !          1863:                {
        !          1864:                  type += 0x10;
        !          1865:                  opbyte = REGNO (fpop->ops[i]) - 17;
        !          1866:                }
        !          1867:              else
        !          1868:                {
        !          1869:                  type += 0x00;
        !          1870:                  opbyte = REGNO (fpop->ops[i]);
        !          1871:                  if (type == 3)
        !          1872:                    opbyte = (opbyte << 4) + opbyte + 1;
        !          1873:                }
        !          1874:              break;
        !          1875: 
        !          1876:            case MEM:
        !          1877:              type += 0x30;
        !          1878:              if (GET_CODE (XEXP (fpop->ops[i], 0)) == PLUS)
        !          1879:                {
        !          1880:                  immed[i] = XEXP (XEXP (fpop->ops[i], 0), 1);
        !          1881:                  opbyte = REGNO (XEXP (XEXP (fpop->ops[i], 0), 0));
        !          1882:                  if (GET_CODE (immed[i]) == CONST_INT)
        !          1883:                    sprintf (desc1, "%d(%s)", INTVAL (immed[i]),
        !          1884:                             reg_names[opbyte]);
        !          1885:                  else
        !          1886:                    sprintf (desc1, "<memory> (%s)", reg_names[opbyte]);
        !          1887:                }
        !          1888:              else if (GET_CODE (XEXP (fpop->ops[i], 0)) == REG)
        !          1889:                {
        !          1890:                  opbyte = REGNO (XEXP (fpop->ops[i], 0));
        !          1891:                  immed[i] = const0_rtx;
        !          1892:                  sprintf (desc1, "(%s)", reg_names[opbyte]);
        !          1893:                }
        !          1894:              else
        !          1895:                {
        !          1896:                  immed[i] = XEXP (fpop->ops[i], 0);
        !          1897:                  opbyte = 0;
        !          1898:                  sprintf(desc1, "<memory>");
        !          1899:                }
        !          1900:              break;
        !          1901: 
        !          1902:            case CONST_INT:
        !          1903:            case CONST_DOUBLE:
        !          1904:            case CONST:
        !          1905:            case SYMBOL_REF:
        !          1906:            case LABEL_REF:
        !          1907:              type += 0x20;
        !          1908:              opbyte = 0;
        !          1909:              immed[i] = fpop->ops[i];
        !          1910:              desc1[0] = '$';
        !          1911:              desc1[1] = '\0';
        !          1912:              break;
        !          1913: 
        !          1914:            default:
        !          1915:              abort ();
        !          1916:            }
        !          1917: 
        !          1918:          /* Save/restore is special.  */
        !          1919:          if (i == 0 && (fpop->opcode == USE || fpop->opcode == CLOBBER))
        !          1920:            type = 0xff, opbyte = INTVAL (fpop->ops[0]), immed[i] = 0;
        !          1921: 
        !          1922:          fprintf (file, "\t.byte 0x%x,0x%x # (%s) %s\n",
        !          1923:                   type, opbyte, desc0, desc1);
        !          1924: 
        !          1925:          size_so_far += 2;
        !          1926:        }
        !          1927: 
        !          1928:       /* If in the middle of a word, round.  */
        !          1929:       if (size_so_far % UNITS_PER_WORD)
        !          1930:        {
        !          1931:          fprintf (file, "\t.space 2\n");
        !          1932:          size_so_far += 2;
        !          1933:        }
        !          1934: 
        !          1935:       for (i = 0; i < fpop->noperands; i++)
        !          1936:        if (immed[i])
        !          1937:          switch (GET_MODE (immed[i]))
        !          1938:            {
        !          1939:            case SImode:
        !          1940:            case VOIDmode:
        !          1941:              size_so_far += 4;
        !          1942:              fprintf (file, "\t.long ");
        !          1943:              output_addr_const (file, immed[i]);
        !          1944:              fprintf (file, "\n");
        !          1945:              break;
        !          1946: 
        !          1947:            case DFmode:
        !          1948:              size_so_far += 4;
        !          1949:            case SFmode:
        !          1950:              size_so_far += 4;
        !          1951:              if (GET_CODE (immed[i]) == CONST_DOUBLE)
        !          1952:                {
        !          1953:                  union real_extract u;
        !          1954: 
        !          1955:                  bcopy (&CONST_DOUBLE_LOW (immed[i]), &u, sizeof u);
        !          1956:                  if (GET_MODE (immed[i]) == DFmode)
        !          1957:                    ASM_OUTPUT_DOUBLE (file, u.d);
        !          1958:                  else
        !          1959:                    ASM_OUTPUT_FLOAT (file, u.d);
        !          1960:                }
        !          1961:              else
        !          1962:                abort ();
        !          1963:              break;
        !          1964: 
        !          1965:            default:
        !          1966:              abort ();
        !          1967:            }
        !          1968:        
        !          1969:       if (size_so_far != fpop->size)
        !          1970:         {
        !          1971:           if (TARGET_FULL_FP_BLOCKS)
        !          1972:            fprintf (file, "\t.space %d\n", fpop->size - size_so_far);
        !          1973:          else
        !          1974:            abort ();
        !          1975:        }
        !          1976:     }
        !          1977: 
        !          1978:   /* Update for next subroutine.  */
        !          1979:   subr_number++;
        !          1980:   text_section ();
        !          1981: }
        !          1982: 
        !          1983:  /* Initialize floating-point operation table.  */
        !          1984: 
        !          1985: static void
        !          1986: init_fpops()
        !          1987: {
        !          1988:   register int i;
        !          1989: 
        !          1990:   first_fpop = last_fpop_in_mem = 0;
        !          1991:   for (i = 0; i < FP_HASH_SIZE; i++)
        !          1992:     fp_hash_table[i] = 0;
        !          1993: }
        !          1994: 
        !          1995: /* Return the offset value of an automatic variable (N_LSYM) having
        !          1996:    the given offset. Basically, we correct by going from a frame pointer to
        !          1997:    stack pointer value.
        !          1998: */
        !          1999: 
        !          2000: int
        !          2001: romp_debugger_auto_correction(offset)
        !          2002:      int offset;
        !          2003: {
        !          2004:   int fp_to_sp;
        !          2005: 
        !          2006:   /* We really want to go from STACK_POINTER_REGNUM to
        !          2007:      FRAME_POINTER_REGNUM, but this isn't defined. So go the other
        !          2008:      direction and negate. */
        !          2009:   INITIAL_ELIMINATION_OFFSET (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM,
        !          2010:                              fp_to_sp);
        !          2011: 
        !          2012:   /* The offset value points somewhere between the frame pointer and
        !          2013:      the stack pointer. What is up from the frame pointer is down from the
        !          2014:      stack pointer. Therefore the negation in the offset value too. */
        !          2015: 
        !          2016:   return -(offset+fp_to_sp+4);
        !          2017: }
        !          2018: 
        !          2019: /* Return the offset value of an argument having
        !          2020:    the given offset. Basically, we correct by going from a arg pointer to
        !          2021:    stack pointer value. */
        !          2022: 
        !          2023: int
        !          2024: romp_debugger_arg_correction (offset)
        !          2025:      int offset;
        !          2026: {
        !          2027:   int fp_to_argp;
        !          2028: 
        !          2029:   INITIAL_ELIMINATION_OFFSET (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM,
        !          2030:                              fp_to_argp);
        !          2031: 
        !          2032:   /* Actually, something different happens if offset is from a floating-point
        !          2033:      register argument, but we don't handle it here.  */
        !          2034: 
        !          2035:   return (offset - fp_to_argp);
        !          2036: }

unix.superglobalmegacorp.com

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