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

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

unix.superglobalmegacorp.com

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