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

1.1     ! root        1: /* Subroutines used for code generation on AMD Am29000.
        !             2:    Copyright (C) 1987, 88, 90, 91, 92, 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: #include <stdio.h>
        !            22: #include "config.h"
        !            23: #include "rtl.h"
        !            24: #include "regs.h"
        !            25: #include "hard-reg-set.h"
        !            26: #include "real.h"
        !            27: #include "insn-config.h"
        !            28: #include "conditions.h"
        !            29: #include "insn-flags.h"
        !            30: #include "output.h"
        !            31: #include "insn-attr.h"
        !            32: #include "flags.h"
        !            33: #include "recog.h"
        !            34: #include "expr.h"
        !            35: #include "obstack.h"
        !            36: #include "tree.h"
        !            37: #include "reload.h"
        !            38: 
        !            39: #define min(A,B)       ((A) < (B) ? (A) : (B))
        !            40: 
        !            41: /* This gives the size in words of the register stack for the current
        !            42:    procedure.  */
        !            43: 
        !            44: static int a29k_regstack_size;
        !            45: 
        !            46: /* This points to the last insn of the insn prologue.  It is set when
        !            47:    an insn without a filled delay slot is found near the start of the
        !            48:    function.  */
        !            49: 
        !            50: static char *a29k_last_prologue_insn;
        !            51: 
        !            52: /* This points to the first insn that will be in the epilogue.  It is null if
        !            53:    no epilogue is required.  */
        !            54: 
        !            55: static char *a29k_first_epilogue_insn;
        !            56: 
        !            57: /* This is nonzero if a a29k_first_epilogue_insn was put in a delay slot.  It
        !            58:    indicates that an intermediate label needs to be written.  */
        !            59: 
        !            60: static int a29k_first_epilogue_insn_used;
        !            61: 
        !            62: /* Location to hold the name of the current function.  We need this prolog to
        !            63:    contain the tag words prior to the declaration.  So the name must be stored
        !            64:    away.  */
        !            65: 
        !            66: char *a29k_function_name;
        !            67: 
        !            68: /* Mapping of registers to debug register numbers.  The only change is
        !            69:    for the frame pointer and the register numbers used for the incoming
        !            70:    arguments.  */
        !            71: 
        !            72: int a29k_debug_reg_map[FIRST_PSEUDO_REGISTER];
        !            73: 
        !            74: /* Save information from a "cmpxx" operation until the branch or scc is
        !            75:    emitted.  */
        !            76: 
        !            77: rtx a29k_compare_op0, a29k_compare_op1;
        !            78: int a29k_compare_fp_p;
        !            79: 
        !            80: /* Gives names for registers.  */
        !            81: extern char *reg_names[];
        !            82: 
        !            83: /* Returns 1 if OP is a 8-bit constant. */
        !            84: 
        !            85: int
        !            86: cint_8_operand (op, mode)
        !            87:      register rtx op;
        !            88:      enum machine_mode mode;
        !            89: {
        !            90:   return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffffff00) == 0;
        !            91: }
        !            92: 
        !            93: /* Returns 1 if OP is a 16-bit constant.  */
        !            94: 
        !            95: int
        !            96: cint_16_operand (op, mode)
        !            97:      rtx op;
        !            98:      enum machine_mode mode;
        !            99: {
        !           100:   return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0;
        !           101: }
        !           102: 
        !           103: /* Returns 1 if OP is a constant that cannot be moved in a single insn.  */
        !           104: 
        !           105: int
        !           106: long_const_operand (op, mode)
        !           107:      register rtx op;
        !           108:      enum machine_mode mode;
        !           109: {
        !           110:   if (! CONSTANT_P (op))
        !           111:     return 0;
        !           112: 
        !           113:   if (TARGET_29050 && GET_CODE (op) == CONST_INT
        !           114:       && (INTVAL (op) & 0xffff) == 0)
        !           115:     return 0;
        !           116: 
        !           117:   return (GET_CODE (op) != CONST_INT
        !           118:          || ((INTVAL (op) & 0xffff0000) != 0
        !           119:              && (INTVAL (op) & 0xffff0000) != 0xffff0000
        !           120:              && INTVAL (op) != 0x80000000));
        !           121: }
        !           122: 
        !           123: /* The following four functions detect constants of 0, 8, 16, and 24 used as
        !           124:    a position in ZERO_EXTRACT operations.  They can either be the appropriate
        !           125:    constant integer or a shift (which will be produced by combine).  */
        !           126: 
        !           127: static int
        !           128: shift_constant_operand (op, mode, val)
        !           129:      rtx op;
        !           130:      enum machine_mode mode;
        !           131:      int val;
        !           132: {
        !           133:   return ((GET_CODE (op) == CONST_INT && INTVAL (op) == val)
        !           134:          || (GET_CODE (op) == ASHIFT
        !           135:              && GET_CODE (XEXP (op, 0)) == CONST_INT
        !           136:              && INTVAL (XEXP (op, 0)) == val / 8
        !           137:              && GET_CODE (XEXP (op, 1)) == CONST_INT
        !           138:              && INTVAL (XEXP (op, 1)) == 3));
        !           139: }
        !           140: 
        !           141: int
        !           142: const_0_operand (op, mode)
        !           143:      rtx op;
        !           144:      enum machine_mode mode;
        !           145: {
        !           146:   return shift_constant_operand (op, mode, 0);
        !           147: }
        !           148: 
        !           149: int
        !           150: const_8_operand (op, mode)
        !           151:      rtx op;
        !           152:      enum machine_mode mode;
        !           153: {
        !           154:   return shift_constant_operand (op, mode, 8);
        !           155: }
        !           156: 
        !           157: int
        !           158: const_16_operand (op, mode)
        !           159:      rtx op;
        !           160:      enum machine_mode mode;
        !           161: {
        !           162:   return shift_constant_operand (op, mode, 16);
        !           163: }
        !           164: 
        !           165: int
        !           166: const_24_operand (op, mode)
        !           167:      rtx op;
        !           168:      enum machine_mode mode;
        !           169: {
        !           170:   return shift_constant_operand (op, mode, 24);
        !           171: }
        !           172: 
        !           173: /* Returns 1 if OP is a floating-point constant of the proper mode.  */
        !           174: 
        !           175: int
        !           176: float_const_operand (op, mode)
        !           177:      rtx op;
        !           178:      enum machine_mode mode;
        !           179: {
        !           180:   return GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == mode;
        !           181: }
        !           182: 
        !           183: /* Returns 1 if OP is a floating-point constant of the proper mode or a
        !           184:    general-purpose register.  */
        !           185: 
        !           186: int
        !           187: gpc_reg_or_float_constant_operand (op, mode)
        !           188:      rtx op;
        !           189:      enum machine_mode mode;
        !           190: {
        !           191:   return float_const_operand (op, mode) || gpc_reg_operand (op, mode);
        !           192: }
        !           193: 
        !           194: /* Returns 1 if OP is an integer constant of the proper mode or a
        !           195:    general-purpose register.  */
        !           196: 
        !           197: int
        !           198: gpc_reg_or_integer_constant_operand (op, mode)
        !           199:      rtx op;
        !           200:      enum machine_mode mode;
        !           201: {
        !           202:   return ((GET_MODE (op) == VOIDmode
        !           203:           && (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE))
        !           204:          || gpc_reg_operand (op, mode));
        !           205: }
        !           206:      
        !           207: /* Returns 1 if OP is a special machine register.  */
        !           208: 
        !           209: int
        !           210: spec_reg_operand (op, mode)
        !           211:      rtx op;
        !           212:      enum machine_mode mode;
        !           213: {
        !           214:   if (GET_CODE (op) != REG || GET_MODE (op) != mode)
        !           215:     return 0;
        !           216: 
        !           217:   switch (GET_MODE_CLASS (mode))
        !           218:     {
        !           219:     case MODE_PARTIAL_INT:
        !           220:       return REGNO (op) >= R_BP && REGNO (op) <= R_CR;
        !           221:     case MODE_INT:
        !           222:       return REGNO (op) >= R_Q && REGNO (op) <= R_EXO;
        !           223:     detault:
        !           224:       return 0;
        !           225:     }
        !           226: }
        !           227: 
        !           228: /* Returns 1 if OP is an accumulator register.  */
        !           229: 
        !           230: int
        !           231: accum_reg_operand (op, mode)
        !           232:      rtx op;
        !           233:      enum machine_mode mode;
        !           234: {
        !           235:   return (GET_CODE (op) == REG
        !           236:          && REGNO (op) >= R_ACC (0) && REGNO (op) <= R_ACC (3));
        !           237: }
        !           238: 
        !           239: /* Returns 1 if OP is a normal data register.  */
        !           240: 
        !           241: int
        !           242: gpc_reg_operand (op, mode)
        !           243:      rtx op;
        !           244:      enum machine_mode mode;
        !           245: {
        !           246:   int regno;
        !           247: 
        !           248:   if (GET_MODE (op) != mode && mode != VOIDmode)
        !           249:     return 0;
        !           250: 
        !           251:   if (GET_CODE (op) == REG)
        !           252:     regno = REGNO (op);
        !           253:   else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
        !           254:     {
        !           255:       regno = REGNO (SUBREG_REG (op));
        !           256:       if (regno < FIRST_PSEUDO_REGISTER)
        !           257:        regno += SUBREG_WORD (op);
        !           258:     }
        !           259:   else
        !           260:     return 0;
        !           261: 
        !           262:   return (regno >= FIRST_PSEUDO_REGISTER || regno < R_BP
        !           263:          || (regno >= R_KR (0) && regno <= R_KR (31)));
        !           264: }
        !           265: 
        !           266: /* Returns 1 if OP is either an 8-bit constant integer or a general register.
        !           267:    If a register, it must be in the proper mode unless MODE is VOIDmode.  */
        !           268: 
        !           269: int
        !           270: srcb_operand (op, mode)
        !           271:       register rtx op;
        !           272:       enum machine_mode mode;
        !           273: {
        !           274:   if (GET_CODE (op) == CONST_INT
        !           275:       && (mode == QImode
        !           276:          || (INTVAL (op) & 0xffffff00) == 0))
        !           277:     return 1;
        !           278: 
        !           279:   if (GET_MODE (op) != mode && mode != VOIDmode)
        !           280:     return 0;
        !           281: 
        !           282:   return gpc_reg_operand (op, mode);
        !           283: }
        !           284: 
        !           285: /* Return 1 if OP is either an immediate or a general register.  This is used
        !           286:    for the input operand of mtsr/mtrsim.  */
        !           287: 
        !           288: int
        !           289: gpc_reg_or_immediate_operand (op, mode)
        !           290:      rtx op;
        !           291:      enum machine_mode mode;
        !           292: {
        !           293:   return gpc_reg_operand (op, mode) || immediate_operand (op, mode);
        !           294: }
        !           295: 
        !           296: /* Return 1 if OP can be used as the second operand of and AND insn.  This
        !           297:    includes srcb_operand and a constant whose complement fits in 8 bits.  */
        !           298: 
        !           299: int
        !           300: and_operand (op, mode)
        !           301:      rtx op;
        !           302:      enum machine_mode mode;
        !           303: {
        !           304:   return (srcb_operand (op, mode)
        !           305:          || (GET_CODE (op) == CONST_INT
        !           306:              && ((unsigned) ((~ INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
        !           307: }
        !           308: 
        !           309: /* Return 1 if OP can be used as the second operand of an ADD insn.
        !           310:    This is the same as above, except we use negative, rather than
        !           311:    complement.   */
        !           312: 
        !           313: int
        !           314: add_operand (op, mode)
        !           315:      rtx op;
        !           316:      enum machine_mode mode;
        !           317: {
        !           318:   return (srcb_operand (op, mode)
        !           319:          || (GET_CODE (op) == CONST_INT
        !           320:              && ((unsigned) ((- INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
        !           321: }
        !           322: 
        !           323: /* Return 1 if OP is a valid address in a CALL_INSN.  These are a SYMBOL_REF
        !           324:    to the current function, all SYMBOL_REFs if TARGET_SMALL_MEMORY, or
        !           325:    a sufficiently-small constant.  */
        !           326: 
        !           327: int
        !           328: call_operand (op, mode)
        !           329:      rtx op;
        !           330:      enum machine_mode mode;
        !           331: {
        !           332:   switch (GET_CODE (op))
        !           333:     {
        !           334:     case SYMBOL_REF:
        !           335:       return (TARGET_SMALL_MEMORY
        !           336:              || (! TARGET_LARGE_MEMORY
        !           337:                  && ((GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op))
        !           338:                      || ! strcmp (XSTR (op, 0), current_function_name))));
        !           339: 
        !           340:     case CONST_INT:
        !           341:       return (unsigned HOST_WIDE_INT) INTVAL (op) < 0x40000;
        !           342: 
        !           343:     default:
        !           344:       return 0;
        !           345:     }
        !           346: }
        !           347: 
        !           348: /* Return 1 if OP can be used as the input operand for a move insn.  */
        !           349: 
        !           350: int
        !           351: in_operand (op, mode)
        !           352:      rtx op;
        !           353:      enum machine_mode mode;
        !           354: {
        !           355:   rtx orig_op = op;
        !           356: 
        !           357:   if (! general_operand (op, mode))
        !           358:     return 0;
        !           359: 
        !           360:   while (GET_CODE (op) == SUBREG)
        !           361:     op = SUBREG_REG (op);
        !           362: 
        !           363:   switch (GET_CODE (op))
        !           364:     {
        !           365:     case REG:
        !           366:       return 1;
        !           367: 
        !           368:     case MEM:
        !           369:       return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);
        !           370: 
        !           371:     case CONST_INT:
        !           372:       if (GET_MODE_CLASS (mode) != MODE_INT
        !           373:          && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
        !           374:        return 0;
        !           375: 
        !           376:       return 1;
        !           377: 
        !           378:     case CONST:
        !           379:     case SYMBOL_REF:
        !           380:     case LABEL_REF:
        !           381:       return (GET_MODE (op) == mode
        !           382:              || mode == SImode || mode == HImode || mode == QImode);
        !           383: 
        !           384:     case CONST_DOUBLE:
        !           385:       return ((GET_MODE_CLASS (mode) == MODE_FLOAT
        !           386:               && mode == GET_MODE (op))
        !           387:              || (GET_MODE (op) == VOIDmode
        !           388:                  && GET_MODE_CLASS (mode) == MODE_INT));
        !           389: 
        !           390:     default:
        !           391:       return 0;
        !           392:     }
        !           393: }
        !           394: 
        !           395: /* Return 1 if OP can be used as the output operand for a move insn.  */
        !           396: 
        !           397: int
        !           398: out_operand (op, mode)
        !           399:      rtx op;
        !           400:      enum machine_mode mode;
        !           401: {
        !           402:   rtx orig_op = op;
        !           403: 
        !           404:   if (! general_operand (op, mode))
        !           405:     return 0;
        !           406: 
        !           407:   while (GET_CODE (op) == SUBREG)
        !           408:     op = SUBREG_REG (op);
        !           409: 
        !           410:   if (GET_CODE (op) == REG)
        !           411:     return (gpc_reg_operand (orig_op, mode)
        !           412:            || spec_reg_operand (orig_op, mode)
        !           413:            || (GET_MODE_CLASS (mode) == MODE_FLOAT
        !           414:                && accum_reg_operand (orig_op, mode)));
        !           415: 
        !           416:   else if (GET_CODE (op) == MEM)
        !           417:     return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);
        !           418:   else
        !           419:     return 0;
        !           420: }
        !           421: 
        !           422: /* Return 1 if OP is an item in memory, given that we are in reload.  */
        !           423: 
        !           424: int
        !           425: reload_memory_operand (op, mode)
        !           426:      rtx op;
        !           427:      enum machine_mode mode;
        !           428: {
        !           429:   int regno = true_regnum (op);
        !           430: 
        !           431:   return (! CONSTANT_P (op)
        !           432:          && (regno == -1
        !           433:              || (GET_CODE (op) == REG
        !           434:                  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
        !           435: }
        !           436: 
        !           437: /* Given an object for which reload_memory_operand is true, return the address
        !           438:    of the operand, taking into account anything that reload may do.  */
        !           439: 
        !           440: rtx
        !           441: a29k_get_reloaded_address (op)
        !           442:      rtx op;
        !           443: {
        !           444:   if (GET_CODE (op) == SUBREG)
        !           445:     {
        !           446:       if (SUBREG_WORD (op) != 0)
        !           447:        abort ();
        !           448: 
        !           449:       op = SUBREG_REG (op);
        !           450:     }
        !           451: 
        !           452:   if (GET_CODE (op) == REG)
        !           453:     op = reg_equiv_mem[REGNO (op)];
        !           454: 
        !           455:   return find_replacement (&XEXP (op, 0));
        !           456: }
        !           457: 
        !           458: /* Subfunction of the following function.  Update the flags of any MEM
        !           459:    found in part of X.  */
        !           460: 
        !           461: static void
        !           462: a29k_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
        !           463:      rtx x;
        !           464:      int in_struct_p, volatile_p, unchanging_p;
        !           465: {
        !           466:   int i;
        !           467: 
        !           468:   switch (GET_CODE (x))
        !           469:     {
        !           470:     case SEQUENCE:
        !           471:     case PARALLEL:
        !           472:       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
        !           473:        a29k_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p,
        !           474:                             unchanging_p);
        !           475:       break;
        !           476: 
        !           477:     case INSN:
        !           478:       a29k_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p,
        !           479:                           unchanging_p);
        !           480:       break;
        !           481: 
        !           482:     case SET:
        !           483:       a29k_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p,
        !           484:                           unchanging_p);
        !           485:       a29k_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, unchanging_p);
        !           486:       break;
        !           487: 
        !           488:     case MEM:
        !           489:       MEM_IN_STRUCT_P (x) = in_struct_p;
        !           490:       MEM_VOLATILE_P (x) = volatile_p;
        !           491:       RTX_UNCHANGING_P (x) = unchanging_p;
        !           492:       break;
        !           493:     }
        !           494: }
        !           495: 
        !           496: /* Given INSN, which is either an INSN or a SEQUENCE generated to
        !           497:    perform a memory operation, look for any MEMs in either a SET_DEST or
        !           498:    a SET_SRC and copy the in-struct, unchanging, and volatile flags from
        !           499:    REF into each of the MEMs found.  If REF is not a MEM, don't do
        !           500:    anything.  */
        !           501: 
        !           502: void
        !           503: a29k_set_memflags (insn, ref)
        !           504:      rtx insn;
        !           505:      rtx ref;
        !           506: {
        !           507:   /* Note that it is always safe to get these flags, though they won't
        !           508:      be what we think if REF is not a MEM.  */
        !           509:   int in_struct_p = MEM_IN_STRUCT_P (ref);
        !           510:   int volatile_p = MEM_VOLATILE_P (ref);
        !           511:   int unchanging_p = RTX_UNCHANGING_P (ref);
        !           512: 
        !           513:   if (GET_CODE (ref) != MEM
        !           514:       || (! in_struct_p && ! volatile_p && ! unchanging_p))
        !           515:     return;
        !           516: 
        !           517:   a29k_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p);
        !           518: }
        !           519: 
        !           520: /* Return 1 if OP is a comparison operator that we have in floating-point.  */
        !           521: 
        !           522: int
        !           523: fp_comparison_operator (op, mode)
        !           524:      rtx op;
        !           525:      enum machine_mode mode;
        !           526: {
        !           527:   return ((mode == VOIDmode || mode == GET_MODE (op))
        !           528:          && (GET_CODE (op) == EQ || GET_CODE (op) == GT ||
        !           529:              GET_CODE (op) == GE));
        !           530: }
        !           531: 
        !           532: /* Return 1 if OP is a valid branch comparison.  */
        !           533: 
        !           534: int
        !           535: branch_operator (op, mode)
        !           536:      rtx op;
        !           537:      enum machine_mode mode;
        !           538: {
        !           539:   return ((mode == VOIDmode || mode == GET_MODE (op))
        !           540:          && (GET_CODE (op) == GE || GET_CODE (op) == LT));
        !           541: }
        !           542: 
        !           543: /* Return 1 if OP is a load multiple operation.  It is known to be a
        !           544:    PARALLEL and the first three sections will be tested.  */
        !           545: 
        !           546: int
        !           547: load_multiple_operation (op, mode)
        !           548:      rtx op;
        !           549:      enum machine_mode mode;
        !           550: {
        !           551:   int count = XVECLEN (op, 0) - 2;
        !           552:   int dest_regno;
        !           553:   rtx src_addr;
        !           554:   int i;
        !           555: 
        !           556:   /* Perform a quick check so we don't blow up below.  */
        !           557:   if (count <= 1
        !           558:       || GET_CODE (XVECEXP (op, 0, 0)) != SET
        !           559:       || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
        !           560:       || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
        !           561:     return 0;
        !           562: 
        !           563:   dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
        !           564:   src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
        !           565: 
        !           566:   for (i = 1; i < count; i++)
        !           567:     {
        !           568:       rtx elt = XVECEXP (op, 0, i + 2);
        !           569: 
        !           570:       if (GET_CODE (elt) != SET
        !           571:          || GET_CODE (SET_DEST (elt)) != REG
        !           572:          || GET_MODE (SET_DEST (elt)) != SImode
        !           573:          || REGNO (SET_DEST (elt)) != dest_regno + i
        !           574:          || GET_CODE (SET_SRC (elt)) != MEM
        !           575:          || GET_MODE (SET_SRC (elt)) != SImode
        !           576:          || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
        !           577:          || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
        !           578:          || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
        !           579:          || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
        !           580:        return 0;
        !           581:     }
        !           582: 
        !           583:   return 1;
        !           584: }
        !           585: 
        !           586: /* Similar, but tests for store multiple.  */
        !           587: 
        !           588: int
        !           589: store_multiple_operation (op, mode)
        !           590:      rtx op;
        !           591:      enum machine_mode mode;
        !           592: {
        !           593:   int num_special = TARGET_NO_STOREM_BUG ? 2 : 1;
        !           594:   int count = XVECLEN (op, 0) - num_special;
        !           595:   int src_regno;
        !           596:   rtx dest_addr;
        !           597:   int i;
        !           598: 
        !           599:   /* Perform a quick check so we don't blow up below.  */
        !           600:   if (count <= 1
        !           601:       || GET_CODE (XVECEXP (op, 0, 0)) != SET
        !           602:       || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
        !           603:       || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
        !           604:     return 0;
        !           605: 
        !           606:   src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
        !           607:   dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
        !           608: 
        !           609:   for (i = 1; i < count; i++)
        !           610:     {
        !           611:       rtx elt = XVECEXP (op, 0, i + num_special);
        !           612: 
        !           613:       if (GET_CODE (elt) != SET
        !           614:          || GET_CODE (SET_SRC (elt)) != REG
        !           615:          || GET_MODE (SET_SRC (elt)) != SImode
        !           616:          || REGNO (SET_SRC (elt)) != src_regno + i
        !           617:          || GET_CODE (SET_DEST (elt)) != MEM
        !           618:          || GET_MODE (SET_DEST (elt)) != SImode
        !           619:          || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
        !           620:          || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
        !           621:          || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
        !           622:          || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
        !           623:        return 0;
        !           624:     }
        !           625: 
        !           626:   return 1;
        !           627: }
        !           628: 
        !           629: /* Given a special register REG and MASK, a value being masked against a
        !           630:    quantity to which the special register is set, return 1 if the masking
        !           631:    operation is built-in to the setting of that special register.  */
        !           632: 
        !           633: int
        !           634: masks_bits_for_special (reg, mask)
        !           635:      rtx reg;
        !           636:      rtx mask;
        !           637: {
        !           638:    int needed_mask_value;
        !           639: 
        !           640:   if (GET_CODE (reg) != REG || GET_CODE (mask) != CONST_INT)
        !           641:     abort ();
        !           642: 
        !           643:   switch (REGNO (reg))
        !           644:     {
        !           645:     case R_BP:
        !           646:     case R_INT:
        !           647:       needed_mask_value = 3;
        !           648:       break;
        !           649: 
        !           650:     case R_FC:
        !           651:       needed_mask_value = 31;
        !           652:       break;
        !           653: 
        !           654:     case R_CR:
        !           655:     case R_LRU:
        !           656:       needed_mask_value = 255;
        !           657:       break;
        !           658: 
        !           659:     case R_FPE:
        !           660:       needed_mask_value = 511;
        !           661:       break;
        !           662: 
        !           663:     case R_MMU:
        !           664:       needed_mask_value = 0x3ff;
        !           665:       break;
        !           666: 
        !           667:     case R_OPS:
        !           668:     case R_CPS:
        !           669:     case R_RBP:
        !           670:     case R_FPS:
        !           671:       needed_mask_value = 0xffff;
        !           672:       break;
        !           673: 
        !           674:     case R_VAB:
        !           675:       needed_mask_value = 0xffff0000;
        !           676:       break;
        !           677: 
        !           678:     case R_Q:
        !           679:     case R_CFG:
        !           680:     case R_CHA:
        !           681:     case R_CHD:
        !           682:     case R_CHC:
        !           683:     case R_TMC:
        !           684:     case R_TMR:
        !           685:     case R_PC0:
        !           686:     case R_PC1:
        !           687:     case R_PC2:
        !           688:       return 0;
        !           689: 
        !           690:     default:
        !           691:       abort ();
        !           692:     }
        !           693: 
        !           694:    return (INTVAL (mask) & ~ needed_mask_value) == 0;
        !           695: }
        !           696: 
        !           697: /* Return nonzero if this label is that of the return point, but there is
        !           698:    a non-null epilogue.  */
        !           699: 
        !           700: int
        !           701: epilogue_operand (op, mode)
        !           702:      rtx op;
        !           703:      enum machine_mode mode;
        !           704: {
        !           705:   return next_active_insn (op) == 0 && a29k_first_epilogue_insn != 0;
        !           706: }
        !           707: 
        !           708: /* Return the register class of a scratch register needed to copy IN into
        !           709:    or out of a register in CLASS in MODE.  If it can be done directly,
        !           710:    NO_REGS is returned.  */
        !           711: 
        !           712: enum reg_class
        !           713: secondary_reload_class (class, mode, in)
        !           714:      enum reg_class class;
        !           715:      enum machine_mode mode;
        !           716:      rtx in;
        !           717: {
        !           718:   int regno = -1;
        !           719:   enum rtx_code code = GET_CODE (in);
        !           720: 
        !           721:   if (! CONSTANT_P (in))
        !           722:     {
        !           723:       regno = true_regnum (in);
        !           724: 
        !           725:       /* A pseudo is the same as memory.  */
        !           726:       if (regno == -1 || regno >= FIRST_PSEUDO_REGISTER)
        !           727:        code = MEM;
        !           728:     }
        !           729: 
        !           730:   /* If we are transferring between memory and a multi-word mode, we need
        !           731:      CR.  */
        !           732: 
        !           733:   if (code == MEM && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
        !           734:     return CR_REGS;
        !           735: 
        !           736:   /* If between memory and a mode smaller than a word without DW being
        !           737:      enabled, we need BP.  */
        !           738: 
        !           739:   if (code == MEM && ! TARGET_DW_ENABLE
        !           740:       && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        !           741:     return BP_REGS;
        !           742: 
        !           743:   /* Otherwise, we can place anything into GENERAL_REGS and can put
        !           744:      GENERAL_REGS into anything.  */
        !           745:   if (class == GENERAL_REGS
        !           746:       || (regno != -1
        !           747:          && (regno < R_BP
        !           748:              || (regno >= R_KR (0) && regno <= R_KR (31)))))
        !           749:     return NO_REGS;
        !           750: 
        !           751:   /* We can place 16-bit constants into a special register.  */
        !           752:   if (code == CONST_INT
        !           753:       && (GET_MODE_BITSIZE (mode) <= 16 || (unsigned) INTVAL (in) <= 65535)
        !           754:       && (class == BP_REGS || class == Q_REGS || class == SPECIAL_REGS))
        !           755:     return NO_REGS;
        !           756: 
        !           757:   /* Otherwise, we need GENERAL_REGS.  */
        !           758:   return GENERAL_REGS;
        !           759: }
        !           760: 
        !           761: /* START is the zero-based incoming argument register index used (0 is 160,
        !           762:    i.e., the first incoming argument register) and COUNT is the number used.
        !           763: 
        !           764:    Mark the corresponding incoming registers as neither fixed nor call used.
        !           765:    For each register used for incoming arguments, we have one less local
        !           766:    register that can be used.  So also mark some high-numbered registers as
        !           767:    fixed.
        !           768: 
        !           769:    Return the first register number to use for the argument.  */
        !           770: 
        !           771: int
        !           772: incoming_reg (start, count)
        !           773:      int start;
        !           774:      int count;
        !           775: {
        !           776:   int i;
        !           777: 
        !           778:   /* We only use 16 argument registers, so truncate at the end of the
        !           779:      area.  */
        !           780:   if (start + count > 16)
        !           781:     count = 16 - start;
        !           782: 
        !           783:   if (! TARGET_NO_REUSE_ARGS)
        !           784:     /* Mark all the used registers as not fixed and saved over calls.  */
        !           785:     for (i = R_AR (start); i < R_AR (start + count); i++)
        !           786:       {
        !           787:        fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 0;
        !           788:        CLEAR_HARD_REG_BIT (fixed_reg_set, i);
        !           789:        CLEAR_HARD_REG_BIT (call_used_reg_set, i);
        !           790:        CLEAR_HARD_REG_BIT (call_fixed_reg_set, i);
        !           791:       }
        !           792: 
        !           793:   /* Shorten the maximum size of the frame.  */
        !           794:   for (i = R_AR (0) - start - count; i < R_AR (0) - start; i++)
        !           795:     {
        !           796:       fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;
        !           797:       SET_HARD_REG_BIT (fixed_reg_set, i);
        !           798:       SET_HARD_REG_BIT (call_used_reg_set, i);
        !           799:       SET_HARD_REG_BIT (call_fixed_reg_set, i);
        !           800:     }
        !           801: 
        !           802:   return R_AR (start);
        !           803: }
        !           804: 
        !           805: /* These routines are used in finding insns to fill delay slots in the
        !           806:    epilogue.  */
        !           807: 
        !           808: /* Return 1 if the current function will adjust the register stack.  */
        !           809: 
        !           810: int
        !           811: needs_regstack_p ()
        !           812: {
        !           813:   int i;
        !           814:   rtx insn;
        !           815: 
        !           816:   if (frame_pointer_needed)
        !           817:     return 1;
        !           818: 
        !           819:   /* If any local register is used, we need to adjust the regstack.  */
        !           820:   for (i = R_LR (127); i >= R_LR (0); i --)
        !           821:     if (regs_ever_live[i])
        !           822:       return 1;
        !           823: 
        !           824:   /* We need a register stack if we make any calls.  */
        !           825:   for (insn = get_insns (); insn; insn = next_insn (insn))
        !           826:     if (GET_CODE (insn) == CALL_INSN
        !           827:        || (GET_CODE (insn) == INSN
        !           828:            && GET_CODE (PATTERN (insn)) == SEQUENCE
        !           829:            && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
        !           830:       return 1;
        !           831: 
        !           832:   /* Otherwise, we don't.  */
        !           833:   return 0;
        !           834: }
        !           835: 
        !           836: /* Return 1 if X uses a local register.  */
        !           837: 
        !           838: int
        !           839: uses_local_reg_p (x)
        !           840:      rtx x;
        !           841: {
        !           842:   char *fmt;
        !           843:   int i, j;
        !           844: 
        !           845:   switch (GET_CODE (x))
        !           846:     {
        !           847:     case REG:
        !           848:       return REGNO (x) >= R_LR (0) && REGNO (x) <= R_FP;
        !           849: 
        !           850:     case CONST_INT:
        !           851:     case CONST:
        !           852:     case PC:
        !           853:     case CC0:
        !           854:     case LABEL_REF:
        !           855:     case SYMBOL_REF:
        !           856:       return 0;
        !           857:     }
        !           858: 
        !           859:   fmt = GET_RTX_FORMAT (GET_CODE (x));
        !           860:   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
        !           861:     {
        !           862:       if (fmt[i] == 'e')
        !           863:        {
        !           864:          if (uses_local_reg_p (XEXP (x, i)))
        !           865:            return 1;
        !           866:        }
        !           867:       else if (fmt[i] == 'E')
        !           868:        {
        !           869:          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
        !           870:            if (uses_local_reg_p (XVECEXP (x, i, j)))
        !           871:              return 1;
        !           872:        }
        !           873:     }
        !           874: 
        !           875:   return 0;
        !           876: }
        !           877: 
        !           878: /* Returns 1 if this function is known to have a null epilogue.  */
        !           879: 
        !           880: int
        !           881: null_epilogue ()
        !           882: {
        !           883:   return (reload_completed && ! needs_regstack_p ()
        !           884:          && get_frame_size () == 0
        !           885:          && current_function_pretend_args_size == 0);
        !           886: }
        !           887: 
        !           888: /* Write out the assembler form of an operand.  Recognize the following
        !           889:    special options:
        !           890: 
        !           891:        %N means write the low-order 8 bits of the negative of the constant
        !           892:        %Q means write a QImode operand (truncate constants to 8 bits)
        !           893:        %M means write the low-order 16 bits of the constant
        !           894:        %m means write the low-order 16 bits shifted left 16 bits
        !           895:        %C means write the low-order 8 bits of the complement of the constant
        !           896:        %b means write `f' is this is a reversed condition, `t' otherwise
        !           897:        %B means write `t' is this is a reversed condition, `f' otherwise
        !           898:        %J means write the 29k opcode part for a comparison operation
        !           899:        %e means write the label with an extra `X' is this is the epilogue
        !           900:                       otherwise the normal label name
        !           901:        %E means write nothing if this insn has a delay slot,
        !           902:                       a nop unless this is the epilogue label, in which case
        !           903:                       write the first epilogue insn
        !           904:        %F means write just the normal operand if the insn has a delay slot;
        !           905:                       otherwise, this is a recursive call so output the
        !           906:                       symbol + 4 and write the first prologue insn in the
        !           907:                       delay slot.
        !           908:        %L means write the register number plus one ("low order" register)
        !           909:                       or the low-order part of a multi-word constant
        !           910:        %O means write the register number plus two
        !           911:        %P means write the register number plus three ("low order" of TImode)
        !           912:        %S means write the number of words in the mode of the operand,
        !           913:                       minus one (for CR)
        !           914:         %V means write the number of elements in a PARALLEL minus 1
        !           915:        %# means write nothing if we have a delay slot, "\n\tnop" otherwise
        !           916:        %* means write the register name for TPC.  */
        !           917: 
        !           918: void
        !           919: print_operand (file, x, code)
        !           920:      FILE *file;
        !           921:      rtx x;
        !           922:      char code;
        !           923: {
        !           924:   char buf[100];
        !           925: 
        !           926:   /* These macros test for integers and extract the low-order bits.  */
        !           927: #define INT_P(X)  \
        !           928: ((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)   \
        !           929:  && GET_MODE (X) == VOIDmode)
        !           930: 
        !           931: #define INT_LOWPART(X) \
        !           932:   (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
        !           933: 
        !           934:   switch (code)
        !           935:     {
        !           936:     case 'Q':
        !           937:       if (GET_CODE (x) == REG)
        !           938:        break;
        !           939:       else if (! INT_P (x))
        !           940:        output_operand_lossage ("invalid %%Q value");
        !           941:       fprintf (file, "%d", INT_LOWPART (x) & 0xff);
        !           942:       return;
        !           943: 
        !           944:     case 'C':
        !           945:       if (! INT_P (x))
        !           946:        output_operand_lossage ("invalid %%C value");
        !           947:       fprintf (file, "%d", (~ INT_LOWPART (x)) & 0xff);
        !           948:       return;
        !           949: 
        !           950:     case 'N':
        !           951:       if (! INT_P (x))
        !           952:        output_operand_lossage ("invalid %%N value");
        !           953:       fprintf (file, "%d", (- INT_LOWPART (x)) & 0xff);
        !           954:       return;
        !           955: 
        !           956:     case 'M':
        !           957:       if (! INT_P (x))
        !           958:        output_operand_lossage ("invalid %%M value");
        !           959:       fprintf (file, "%d", INT_LOWPART (x) & 0xffff);
        !           960:       return;
        !           961: 
        !           962:     case 'm':
        !           963:       if (! INT_P (x))
        !           964:        output_operand_lossage ("invalid %%m value");
        !           965:       fprintf (file, "%d", (INT_LOWPART (x) & 0xffff) << 16);
        !           966:       return;
        !           967: 
        !           968:     case 'b':
        !           969:       if (GET_CODE (x) == GE)
        !           970:        fprintf (file, "f");
        !           971:       else
        !           972:        fprintf (file, "t");
        !           973:       return;
        !           974: 
        !           975:     case 'B':
        !           976:       if (GET_CODE (x) == GE)
        !           977:        fprintf (file, "t");
        !           978:       else
        !           979:        fprintf (file, "f");
        !           980:       return;
        !           981: 
        !           982:     case 'J':
        !           983:       /* It so happens that the RTX names for the conditions are the same as
        !           984:         the 29k's insns except for "ne", which requires "neq".  */
        !           985:       fprintf (file, GET_RTX_NAME (GET_CODE (x)));
        !           986:       if (GET_CODE (x) == NE)
        !           987:        fprintf (file, "q");
        !           988:       return;
        !           989: 
        !           990:     case 'e':
        !           991:       if (optimize && flag_delayed_branch
        !           992:          && a29k_last_prologue_insn == 0 && epilogue_operand (x, VOIDmode)
        !           993:          && dbr_sequence_length () == 0)
        !           994:        {
        !           995:          /* We need to output the label number of the last label in the
        !           996:             function, which is not necessarily X since there might be
        !           997:             a USE insn in between.  First go forward to the last insn, then
        !           998:             back up to a label.  */
        !           999:          while (NEXT_INSN (x) != 0)
        !          1000:            x = NEXT_INSN (x);
        !          1001: 
        !          1002:          while (GET_CODE (x) != CODE_LABEL)
        !          1003:            x = PREV_INSN (x);
        !          1004: 
        !          1005:          ASM_GENERATE_INTERNAL_LABEL (buf, "LX", CODE_LABEL_NUMBER (x));
        !          1006:          assemble_name (file, buf);
        !          1007:        }
        !          1008:       else
        !          1009:        output_asm_label (x);
        !          1010:       return;
        !          1011: 
        !          1012:     case 'E':
        !          1013:       if (dbr_sequence_length ())
        !          1014:        ;
        !          1015:       else if (a29k_last_prologue_insn)
        !          1016:        {
        !          1017:          fprintf (file, "\n\t%s", a29k_last_prologue_insn);
        !          1018:          a29k_last_prologue_insn = 0;
        !          1019:        }
        !          1020:       else if (optimize && flag_delayed_branch
        !          1021:               && epilogue_operand (x, VOIDmode))
        !          1022:        {
        !          1023:          fprintf (file, "\n\t%s", a29k_first_epilogue_insn);
        !          1024:          a29k_first_epilogue_insn_used = 1;
        !          1025:        }
        !          1026:       else
        !          1027:        fprintf (file, "\n\tnop");
        !          1028:       return;
        !          1029:       
        !          1030:     case 'F':
        !          1031:       output_addr_const (file, x);
        !          1032:       if (dbr_sequence_length () == 0)
        !          1033:        {
        !          1034:          if (GET_CODE (x) == SYMBOL_REF
        !          1035:              && ! strcmp (XSTR (x, 0), current_function_name))
        !          1036:            fprintf (file, "+4\n\t%s,%d",
        !          1037:                     a29k_regstack_size >= 64 ? "const gr121" : "sub gr1,gr1",
        !          1038:                     a29k_regstack_size * 4);
        !          1039:          else
        !          1040:            fprintf (file, "\n\tnop");
        !          1041:        }
        !          1042:       return;
        !          1043: 
        !          1044:     case 'L':
        !          1045:       if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
        !          1046:        {
        !          1047:          union real_extract u;
        !          1048: 
        !          1049:          bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u);
        !          1050:          fprintf (file, "$double1(%.20e)", u.d);
        !          1051:        }
        !          1052:       else if (GET_CODE (x) == REG)
        !          1053:        fprintf (file, "%s", reg_names[REGNO (x) + 1]);
        !          1054:       else
        !          1055:        output_operand_lossage ("invalid %%L value");
        !          1056:       return;
        !          1057: 
        !          1058:     case 'O':
        !          1059:       if (GET_CODE (x) != REG)
        !          1060:        output_operand_lossage ("invalid %%O value");
        !          1061:       fprintf (file, "%s", reg_names[REGNO (x) + 2]);
        !          1062:       return;
        !          1063: 
        !          1064:     case 'P':
        !          1065:       if (GET_CODE (x) != REG)
        !          1066:        output_operand_lossage ("invalid %%P value");
        !          1067:       fprintf (file, "%s", reg_names[REGNO (x) + 3]);
        !          1068:       return;
        !          1069: 
        !          1070:     case 'S':
        !          1071:       fprintf (file, "%d", (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD)-1);
        !          1072:       return;
        !          1073: 
        !          1074:     case 'V':
        !          1075:       if (GET_CODE (x) != PARALLEL)
        !          1076:        output_operand_lossage ("invalid %%V value");
        !          1077:       fprintf (file, "%d", XVECLEN (x, 0) - 2);
        !          1078:       return;
        !          1079: 
        !          1080:     case '#':
        !          1081:       if (dbr_sequence_length () == 0)
        !          1082:        {
        !          1083:          if (a29k_last_prologue_insn)
        !          1084:            {
        !          1085:              fprintf (file, "\n\t%s", a29k_last_prologue_insn);
        !          1086:              a29k_last_prologue_insn = 0;
        !          1087:            }
        !          1088:          else
        !          1089:            fprintf (file, "\n\tnop");
        !          1090:        }
        !          1091:       return;
        !          1092: 
        !          1093:     case '*':
        !          1094:       fprintf (file, "%s", reg_names [R_TPC]);
        !          1095:       return;
        !          1096:     }
        !          1097: 
        !          1098:   if (GET_CODE (x) == REG)
        !          1099:     fprintf (file, "%s", reg_names [REGNO (x)]);
        !          1100: 
        !          1101:   else if (GET_CODE (x) == MEM)
        !          1102:     output_address (XEXP (x, 0));
        !          1103: 
        !          1104:   else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == SUBREG
        !          1105:           && GET_CODE (SUBREG_REG (XEXP (x, 0))) == CONST_DOUBLE)
        !          1106:     {
        !          1107:       union real_extract u;
        !          1108: 
        !          1109:       if (GET_MODE (SUBREG_REG (XEXP (x, 0))) == SFmode)
        !          1110:        fprintf (file, "$float");
        !          1111:       else
        !          1112:        fprintf (file, "$double%d", SUBREG_WORD (XEXP (x, 0)));
        !          1113:       bcopy (&CONST_DOUBLE_LOW (SUBREG_REG (XEXP (x, 0))), &u, sizeof u);
        !          1114:       fprintf (file, "(%.20e)", u.d);
        !          1115:     }
        !          1116: 
        !          1117:   else if (GET_CODE (x) == CONST_DOUBLE
        !          1118:           && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
        !          1119:     {
        !          1120:       union real_extract u;
        !          1121: 
        !          1122:       bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u);
        !          1123:       fprintf (file, "$%s(%.20e)",
        !          1124:               GET_MODE (x) == SFmode ? "float" : "double0", u.d);
        !          1125:     }
        !          1126: 
        !          1127:   else
        !          1128:     output_addr_const (file, x);
        !          1129: }
        !          1130: 
        !          1131: /* This page contains routines to output function prolog and epilog code. */
        !          1132: 
        !          1133: /* Output function prolog code to file FILE.  Memory stack size is SIZE.
        !          1134: 
        !          1135:    Also sets register names for incoming arguments and frame pointer.  */
        !          1136: 
        !          1137: void
        !          1138: output_prolog (file, size)
        !          1139:      FILE *file;
        !          1140:      int size;
        !          1141: {
        !          1142:   int makes_calls = 0;
        !          1143:   int arg_count = 0;
        !          1144:   rtx insn;
        !          1145:   int i;
        !          1146:   unsigned int tag_word;
        !          1147: 
        !          1148:   /* See if we make any calls.  We need to set lr1 if so.  */
        !          1149:   for (insn = get_insns (); insn; insn = next_insn (insn))
        !          1150:     if (GET_CODE (insn) == CALL_INSN
        !          1151:        || (GET_CODE (insn) == INSN
        !          1152:            && GET_CODE (PATTERN (insn)) == SEQUENCE
        !          1153:            && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
        !          1154:       {
        !          1155:        makes_calls = 1;
        !          1156:        break;
        !          1157:       }
        !          1158: 
        !          1159:   /* Find the highest local register used.  */
        !          1160:   for (i = R_LR (127); i >= R_LR (0); i--)
        !          1161:     if (regs_ever_live[i])
        !          1162:       break;
        !          1163: 
        !          1164:   a29k_regstack_size = i - (R_LR (0) - 1);
        !          1165: 
        !          1166:   /* If calling routines, ensure we count lr0 & lr1.  */
        !          1167:   if (makes_calls && a29k_regstack_size < 2)
        !          1168:     a29k_regstack_size = 2;
        !          1169: 
        !          1170:   /* Count frame pointer and align to 8 byte boundary (even number of
        !          1171:      registers).  */
        !          1172:   a29k_regstack_size += frame_pointer_needed;
        !          1173:   if (a29k_regstack_size & 1) a29k_regstack_size++;
        !          1174: 
        !          1175:   /* See how many incoming arguments we have in registers.  */
        !          1176:   for (i = R_AR (0); i < R_AR (16); i++)
        !          1177:     if (! fixed_regs[i])
        !          1178:       arg_count++;
        !          1179: 
        !          1180:   /* The argument count includes the caller's lr0 and lr1.  */
        !          1181:   arg_count += 2;
        !          1182: 
        !          1183:   /* Set the names and numbers of the frame pointer and incoming argument
        !          1184:      registers.  */
        !          1185: 
        !          1186:   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        !          1187:     a29k_debug_reg_map[i] = i;
        !          1188: 
        !          1189:   reg_names[FRAME_POINTER_REGNUM] = reg_names[R_LR (a29k_regstack_size - 1)];
        !          1190:   a29k_debug_reg_map[FRAME_POINTER_REGNUM] = R_LR (a29k_regstack_size - 1);
        !          1191: 
        !          1192:   for (i = 0; i < 16; i++)
        !          1193:     {
        !          1194:       reg_names[R_AR (i)] = reg_names[R_LR (a29k_regstack_size + i + 2)];
        !          1195:       a29k_debug_reg_map[R_AR (i)] = R_LR (a29k_regstack_size + i + 2);
        !          1196:     }
        !          1197: 
        !          1198:   /* Compute memory stack size.  Add in number of bytes that the we should
        !          1199:      push and pretend the caller did and the size of outgoing arguments.
        !          1200:      Then round to a doubleword boundary.  */
        !          1201:   size += (current_function_pretend_args_size
        !          1202:           + current_function_outgoing_args_size);
        !          1203:   size = (size + 7) & ~7;
        !          1204: 
        !          1205:   /* Write header words.  See if one or two word form.  */
        !          1206:   tag_word = (frame_pointer_needed ? 0x400000 : 0) + (arg_count << 16);
        !          1207: 
        !          1208:   if (size / 8 > 0xff)
        !          1209:     fprintf (file, "\t.word %d, 0x%0x\n", (size / 8) << 2,
        !          1210:             0x800000 + tag_word);
        !          1211:   else
        !          1212:     fprintf (file, "\t.word 0x%0x\n", tag_word + ((size / 8) << 3));
        !          1213: 
        !          1214:   /* Define the function name.  */
        !          1215:   assemble_name (file, a29k_function_name);
        !          1216:   fprintf (file, ":\n");
        !          1217: 
        !          1218:   /* Push the register stack by the proper amount.  There are two possible
        !          1219:      ways to do this.  */
        !          1220:   if (a29k_regstack_size >= 256/4)
        !          1221:     fprintf (file, "\tconst %s,%d\n\tsub gr1,gr1,%s\n",
        !          1222:             reg_names[R_TAV], a29k_regstack_size * 4, reg_names[R_TAV]);
        !          1223:   else if (a29k_regstack_size)
        !          1224:     fprintf (file, "\tsub gr1,gr1,%d\n", a29k_regstack_size * 4);
        !          1225: 
        !          1226:   /* Test that the registers are available.  */
        !          1227:   if (a29k_regstack_size)
        !          1228:     fprintf (file, "\tasgeu V_%sSPILL,gr1,%s\n",
        !          1229:             TARGET_KERNEL_REGISTERS ? "K" : "", reg_names[R_RAB]);
        !          1230: 
        !          1231:   /* Set up frame pointer, if one is needed.  */
        !          1232:   if (frame_pointer_needed)
        !          1233:     fprintf (file, "\tsll %s,%s,0\n", reg_names[FRAME_POINTER_REGNUM],
        !          1234:             reg_names[R_MSP]);
        !          1235: 
        !          1236:   /* Make room for any frame space.  There are three ways to do this.  */
        !          1237:   if (size >= 256)
        !          1238:     {
        !          1239:       fprintf (file, "\tconst %s,%d\n", reg_names[R_TAV], size);
        !          1240:       if (size >= 65536)
        !          1241:        fprintf (file, "\tconsth %s,%d\n", reg_names[R_TAV], size);
        !          1242:       if (TARGET_STACK_CHECK)
        !          1243:        fprintf (file, "\tcall %s,__msp_check\n", reg_names[R_TPC]);
        !          1244:       fprintf (file, "\tsub %s,%s,%s\n",
        !          1245:               reg_names[R_MSP], reg_names[R_MSP], reg_names[R_TAV]);
        !          1246:     }
        !          1247:   else if (size)
        !          1248:     {
        !          1249:       if (TARGET_STACK_CHECK)
        !          1250:        fprintf (file, "\tcall %s,__msp_check\n", reg_names[R_TPC]);
        !          1251:       fprintf (file, "\tsub %s,%s,%d\n",
        !          1252:               reg_names[R_MSP], reg_names[R_MSP], size);
        !          1253:     }
        !          1254: 
        !          1255:   /* If this routine will make calls, set lr1.  If we see an insn that
        !          1256:      can use a delay slot before a call or jump, save this insn for that
        !          1257:      slot (this condition is equivalent to seeing if we have an insn that
        !          1258:      needs delay slots before an insn that has a filled delay slot).  */
        !          1259:   a29k_last_prologue_insn = 0;
        !          1260:   if (makes_calls)
        !          1261:     {
        !          1262:       i = (a29k_regstack_size + arg_count) * 4;
        !          1263:       if (i >= 256)
        !          1264:        fprintf (file, "\tconst %s,%d\n\tadd lr1,gr1,%s\n",
        !          1265:                 reg_names[R_TAV], i, reg_names[R_TAV]);
        !          1266:       else
        !          1267:        {
        !          1268:          if (optimize && flag_delayed_branch)
        !          1269:            for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
        !          1270:              {
        !          1271:                if (GET_CODE (insn) == CODE_LABEL
        !          1272:                    || (GET_CODE (insn) == INSN
        !          1273:                        && GET_CODE (PATTERN (insn)) == SEQUENCE))
        !          1274:                  break;
        !          1275: 
        !          1276:                if (GET_CODE (insn) == NOTE
        !          1277:                    || (GET_CODE (insn) == INSN
        !          1278:                        && (GET_CODE (PATTERN (insn)) == USE
        !          1279:                            || GET_CODE (PATTERN (insn)) == CLOBBER)))
        !          1280:                  continue;
        !          1281: 
        !          1282:                if (num_delay_slots (insn) > 0)
        !          1283:                  {
        !          1284:                    a29k_last_prologue_insn = (char *) oballoc (100);
        !          1285:                    sprintf (a29k_last_prologue_insn, "add lr1,gr1,%d", i);
        !          1286:                    break;
        !          1287:                  }
        !          1288:              }
        !          1289: 
        !          1290:          if (a29k_last_prologue_insn == 0)
        !          1291:            fprintf (file, "\tadd lr1,gr1,%d\n", i);
        !          1292:        }
        !          1293:     }
        !          1294: 
        !          1295:   /* Compute the first insn of the epilogue.  */
        !          1296:   a29k_first_epilogue_insn_used = 0;
        !          1297: 
        !          1298:   if (size == 0 && a29k_regstack_size == 0 && ! frame_pointer_needed)
        !          1299:     a29k_first_epilogue_insn = 0;
        !          1300:   else
        !          1301:     a29k_first_epilogue_insn = (char *) oballoc (100);
        !          1302: 
        !          1303:   if (frame_pointer_needed)
        !          1304:     sprintf (a29k_first_epilogue_insn, "sll %s,%s,0",
        !          1305:             reg_names[R_MSP], reg_names[FRAME_POINTER_REGNUM]);
        !          1306:   else if (a29k_regstack_size)
        !          1307:     {
        !          1308:       if (a29k_regstack_size >= 256 / 4)
        !          1309:        sprintf (a29k_first_epilogue_insn, "const %s,%d",
        !          1310:                 reg_names[R_TAV], a29k_regstack_size * 4);
        !          1311:       else
        !          1312:        sprintf (a29k_first_epilogue_insn, "add gr1,gr1,%d",
        !          1313:                 a29k_regstack_size * 4);
        !          1314:     }
        !          1315:   else if (size)
        !          1316:     {
        !          1317:       if (size >= 256)
        !          1318:        sprintf (a29k_first_epilogue_insn, "const %s,%d",
        !          1319:                 reg_names[R_TAV], size);
        !          1320:       else
        !          1321:        sprintf (a29k_first_epilogue_insn, "add %s,%s,%d",
        !          1322:                 reg_names[R_MSP], reg_names[R_MSP], size);
        !          1323:     }
        !          1324: }
        !          1325: 
        !          1326: /* Call this after writing what might be the first instruction of the
        !          1327:    epilogue.  If that first insn was used in a delay slot, an intermediate
        !          1328:    label is written.  */
        !          1329: 
        !          1330: static void
        !          1331: check_epilogue_internal_label (file)
        !          1332:      FILE *file;
        !          1333: {
        !          1334:   rtx insn;
        !          1335: 
        !          1336:   if (! a29k_first_epilogue_insn_used)
        !          1337:     return;
        !          1338: 
        !          1339:   for (insn = get_last_insn ();
        !          1340:        GET_CODE (insn) != CODE_LABEL;
        !          1341:        insn = PREV_INSN (insn))
        !          1342:     ;
        !          1343: 
        !          1344:   ASM_OUTPUT_INTERNAL_LABEL (file, "LX", CODE_LABEL_NUMBER (insn));
        !          1345:   a29k_first_epilogue_insn_used = 0;
        !          1346: }
        !          1347: 
        !          1348: /* Output the epilog of the last procedure to file FILE.  SIZE is the memory
        !          1349:    stack size.  The register stack size is in the variable
        !          1350:    A29K_REGSTACK_SIZE.  */
        !          1351: 
        !          1352: void
        !          1353: output_epilog (file, size)
        !          1354:      FILE *file;
        !          1355:      int size;
        !          1356: {
        !          1357:   rtx insn;
        !          1358:   int locals_unavailable = 0;  /* True until after first insn
        !          1359:                                   after gr1 update. */
        !          1360: 
        !          1361:   /* If we hit a BARRIER before a real insn or CODE_LABEL, we don't
        !          1362:      need to do anything because we are never jumped to.  */
        !          1363:   insn = get_last_insn ();
        !          1364:   if (GET_CODE (insn) == NOTE)
        !          1365:     insn = prev_nonnote_insn (insn);
        !          1366: 
        !          1367:   if (insn && GET_CODE (insn) == BARRIER)
        !          1368:     return;
        !          1369: 
        !          1370:   /* If a frame pointer was needed we must restore the memory stack pointer
        !          1371:      before adjusting the register stack.  */
        !          1372:   if (frame_pointer_needed)
        !          1373:     {
        !          1374:       fprintf (file, "\tsll %s,%s,0\n",
        !          1375:               reg_names[R_MSP], reg_names[FRAME_POINTER_REGNUM]);
        !          1376:       check_epilogue_internal_label (file);
        !          1377:     }
        !          1378: 
        !          1379:   /* Restore the register stack.  There are two ways to do this.  */
        !          1380:   if (a29k_regstack_size)
        !          1381:     {
        !          1382:       if (a29k_regstack_size >= 256/4)
        !          1383:        {
        !          1384:          fprintf (file, "\tconst %s,%d\n",
        !          1385:                   reg_names[R_TAV], a29k_regstack_size * 4);
        !          1386:          check_epilogue_internal_label (file);
        !          1387:          fprintf (file, "\tadd gr1,gr1,%s\n", reg_names[R_TAV]);
        !          1388:        }
        !          1389:       else
        !          1390:        {
        !          1391:          fprintf (file, "\tadd gr1,gr1,%d\n", a29k_regstack_size * 4);
        !          1392:          check_epilogue_internal_label (file);
        !          1393:        }
        !          1394:       locals_unavailable = 1;
        !          1395:     }
        !          1396: 
        !          1397:   /* Restore the memory stack pointer if there is no frame pointer.
        !          1398:      Adjust the size to include any pretend arguments and pushed
        !          1399:      arguments and round to doubleword boundary.  */
        !          1400:   size += (current_function_pretend_args_size
        !          1401:           + current_function_outgoing_args_size);
        !          1402:   size = (size + 7) & ~7;
        !          1403: 
        !          1404:   if (size && ! frame_pointer_needed)
        !          1405:     {
        !          1406:       if (size >= 256)
        !          1407:        {
        !          1408:          fprintf (file, "\tconst %s,%d\n", reg_names[R_TAV], size);
        !          1409:          check_epilogue_internal_label (file);
        !          1410:          locals_unavailable = 0;
        !          1411:          if (size >= 65536)
        !          1412:            fprintf (file, "\tconsth %s,%d\n", reg_names[R_TAV], size);
        !          1413:          fprintf (file, "\tadd %s,%s,%s\n",
        !          1414:                   reg_names[R_MSP], reg_names[R_MSP], reg_names[R_TAV]);
        !          1415:        }
        !          1416:       else
        !          1417:        {
        !          1418:          fprintf (file, "\tadd %s,%s,%d\n",
        !          1419:                   reg_names[R_MSP], reg_names[R_MSP], size);
        !          1420:          check_epilogue_internal_label (file);
        !          1421:          locals_unavailable = 0;
        !          1422:        }
        !          1423:     }
        !          1424: 
        !          1425:   if (locals_unavailable)
        !          1426:     {
        !          1427:       /* If we have an insn for this delay slot, write it.  */
        !          1428:       if (current_function_epilogue_delay_list)
        !          1429:        final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
        !          1430:                         file, 1, -2, 1);
        !          1431:       else
        !          1432:        fprintf (file, "\tnop\n");
        !          1433:     }
        !          1434: 
        !          1435:   fprintf (file, "\tjmpi lr0\n");
        !          1436:   if (a29k_regstack_size)
        !          1437:     fprintf (file, "\tasleu V_%sFILL,lr1,%s\n",
        !          1438:             TARGET_KERNEL_REGISTERS ? "K" : "", reg_names[R_RFB]);
        !          1439:   else if (current_function_epilogue_delay_list)
        !          1440:     final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
        !          1441:                     file, 1, -2, 1);
        !          1442:   else
        !          1443:     fprintf (file, "\tnop\n");
        !          1444: }

unix.superglobalmegacorp.com

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