aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/a29k/a29k.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/a29k/a29k.c')
-rw-r--r--gcc/config/a29k/a29k.c1513
1 files changed, 0 insertions, 1513 deletions
diff --git a/gcc/config/a29k/a29k.c b/gcc/config/a29k/a29k.c
deleted file mode 100644
index e30340b49ce..00000000000
--- a/gcc/config/a29k/a29k.c
+++ /dev/null
@@ -1,1513 +0,0 @@
-/* Subroutines used for code generation on AMD Am29000.
- Copyright (C) 1987, 88, 90-94, 1995 Free Software Foundation, Inc.
- Contributed by Richard Kenner (kenner@nyu.edu)
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#include <stdio.h>
-#include "config.h"
-#include "rtl.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "real.h"
-#include "insn-config.h"
-#include "conditions.h"
-#include "insn-flags.h"
-#include "output.h"
-#include "insn-attr.h"
-#include "flags.h"
-#include "recog.h"
-#include "expr.h"
-#include "obstack.h"
-#include "tree.h"
-#include "reload.h"
-
-#define min(A,B) ((A) < (B) ? (A) : (B))
-
-/* This gives the size in words of the register stack for the current
- procedure. */
-
-static int a29k_regstack_size;
-
-/* This points to the last insn of the insn prologue. It is set when
- an insn without a filled delay slot is found near the start of the
- function. */
-
-static char *a29k_last_prologue_insn;
-
-/* This points to the first insn that will be in the epilogue. It is null if
- no epilogue is required. */
-
-static char *a29k_first_epilogue_insn;
-
-/* This is nonzero if a a29k_first_epilogue_insn was put in a delay slot. It
- indicates that an intermediate label needs to be written. */
-
-static int a29k_first_epilogue_insn_used;
-
-/* Location to hold the name of the current function. We need this prolog to
- contain the tag words prior to the declaration. So the name must be stored
- away. */
-
-char *a29k_function_name;
-
-/* Mapping of registers to debug register numbers. The only change is
- for the frame pointer and the register numbers used for the incoming
- arguments. */
-
-int a29k_debug_reg_map[FIRST_PSEUDO_REGISTER];
-
-/* Save information from a "cmpxx" operation until the branch or scc is
- emitted. */
-
-rtx a29k_compare_op0, a29k_compare_op1;
-int a29k_compare_fp_p;
-
-/* Gives names for registers. */
-extern char *reg_names[];
-
-/* Returns 1 if OP is a 8-bit constant. */
-
-int
-cint_8_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffffff00) == 0;
-}
-
-/* Returns 1 if OP is a 16-bit constant. */
-
-int
-cint_16_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0;
-}
-
-/* Returns 1 if OP is a constant that cannot be moved in a single insn. */
-
-int
-long_const_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- if (! CONSTANT_P (op))
- return 0;
-
- if (TARGET_29050 && GET_CODE (op) == CONST_INT
- && (INTVAL (op) & 0xffff) == 0)
- return 0;
-
- return (GET_CODE (op) != CONST_INT
- || ((INTVAL (op) & 0xffff0000) != 0
- && (INTVAL (op) & 0xffff0000) != 0xffff0000
- && INTVAL (op) != 0x80000000));
-}
-
-/* The following four functions detect constants of 0, 8, 16, and 24 used as
- a position in ZERO_EXTRACT operations. They can either be the appropriate
- constant integer or a shift (which will be produced by combine). */
-
-static int
-shift_constant_operand (op, mode, val)
- rtx op;
- enum machine_mode mode;
- int val;
-{
- return ((GET_CODE (op) == CONST_INT && INTVAL (op) == val)
- || (GET_CODE (op) == ASHIFT
- && GET_CODE (XEXP (op, 0)) == CONST_INT
- && INTVAL (XEXP (op, 0)) == val / 8
- && GET_CODE (XEXP (op, 1)) == CONST_INT
- && INTVAL (XEXP (op, 1)) == 3));
-}
-
-int
-const_0_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return shift_constant_operand (op, mode, 0);
-}
-
-int
-const_8_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return shift_constant_operand (op, mode, 8);
-}
-
-int
-const_16_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return shift_constant_operand (op, mode, 16);
-}
-
-int
-const_24_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return shift_constant_operand (op, mode, 24);
-}
-
-/* Returns 1 if OP is a floating-point constant of the proper mode. */
-
-int
-float_const_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == mode;
-}
-
-/* Returns 1 if OP is a floating-point constant of the proper mode or a
- general-purpose register. */
-
-int
-gpc_reg_or_float_constant_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return float_const_operand (op, mode) || gpc_reg_operand (op, mode);
-}
-
-/* Returns 1 if OP is an integer constant of the proper mode or a
- general-purpose register. */
-
-int
-gpc_reg_or_integer_constant_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return ((GET_MODE (op) == VOIDmode
- && (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE))
- || gpc_reg_operand (op, mode));
-}
-
-/* Returns 1 if OP is a special machine register. */
-
-int
-spec_reg_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- if (GET_CODE (op) != REG || GET_MODE (op) != mode)
- return 0;
-
- switch (GET_MODE_CLASS (mode))
- {
- case MODE_PARTIAL_INT:
- return REGNO (op) >= R_BP && REGNO (op) <= R_CR;
- case MODE_INT:
- return REGNO (op) >= R_Q && REGNO (op) <= R_EXO;
- default:
- return 0;
- }
-}
-
-/* Returns 1 if OP is an accumulator register. */
-
-int
-accum_reg_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return (GET_CODE (op) == REG
- && REGNO (op) >= R_ACU (0) && REGNO (op) <= R_ACU (3));
-}
-
-/* Returns 1 if OP is a normal data register. */
-
-int
-gpc_reg_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- int regno;
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- if (GET_CODE (op) == REG)
- regno = REGNO (op);
- else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
- {
- regno = REGNO (SUBREG_REG (op));
- if (regno < FIRST_PSEUDO_REGISTER)
- regno += SUBREG_WORD (op);
- }
- else
- return 0;
-
- return (regno >= FIRST_PSEUDO_REGISTER || regno < R_BP
- || (regno >= R_KR (0) && regno <= R_KR (31)));
-}
-
-/* Returns 1 if OP is either an 8-bit constant integer or a general register.
- If a register, it must be in the proper mode unless MODE is VOIDmode. */
-
-int
-srcb_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- if (GET_CODE (op) == CONST_INT
- && (mode == QImode
- || (INTVAL (op) & 0xffffff00) == 0))
- return 1;
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- return gpc_reg_operand (op, mode);
-}
-
-int
-cmplsrcb_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- if (GET_CODE (op) == CONST_INT
- && (mode == QImode
- || (INTVAL (op) & 0xffffff00) == 0xffffff00))
- return 1;
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- return gpc_reg_operand (op, mode);
-}
-
-/* Return 1 if OP is either an immediate or a general register. This is used
- for the input operand of mtsr/mtrsim. */
-
-int
-gpc_reg_or_immediate_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return gpc_reg_operand (op, mode) || immediate_operand (op, mode);
-}
-
-/* Return 1 if OP can be used as the second operand of and AND insn. This
- includes srcb_operand and a constant whose complement fits in 8 bits. */
-
-int
-and_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return (srcb_operand (op, mode)
- || (GET_CODE (op) == CONST_INT
- && ((unsigned) ((~ INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
-}
-
-/* Return 1 if OP can be used as the second operand of an ADD insn.
- This is the same as above, except we use negative, rather than
- complement. */
-
-int
-add_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return (srcb_operand (op, mode)
- || (GET_CODE (op) == CONST_INT
- && ((unsigned) ((- INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
-}
-
-/* Return 1 if OP is a valid address in a CALL_INSN. These are a SYMBOL_REF
- to the current function, all SYMBOL_REFs if TARGET_SMALL_MEMORY, or
- a sufficiently-small constant. */
-
-int
-call_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- switch (GET_CODE (op))
- {
- case SYMBOL_REF:
- return (TARGET_SMALL_MEMORY
- || (! TARGET_LARGE_MEMORY
- && ((GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op))
- || ! strcmp (XSTR (op, 0), current_function_name))));
-
- case CONST_INT:
- return (unsigned HOST_WIDE_INT) INTVAL (op) < 0x40000;
-
- default:
- return 0;
- }
-}
-
-/* Return 1 if OP can be used as the input operand for a move insn. */
-
-int
-in_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- rtx orig_op = op;
-
- if (! general_operand (op, mode))
- return 0;
-
- while (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- switch (GET_CODE (op))
- {
- case REG:
- return 1;
-
- case MEM:
- return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);
-
- case CONST_INT:
- if (GET_MODE_CLASS (mode) != MODE_INT
- && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
- return 0;
-
- return 1;
-
- case CONST:
- case SYMBOL_REF:
- case LABEL_REF:
- return (GET_MODE (op) == mode
- || mode == SImode || mode == HImode || mode == QImode);
-
- case CONST_DOUBLE:
- return ((GET_MODE_CLASS (mode) == MODE_FLOAT
- && mode == GET_MODE (op))
- || (GET_MODE (op) == VOIDmode
- && GET_MODE_CLASS (mode) == MODE_INT));
-
- default:
- return 0;
- }
-}
-
-/* Return 1 if OP can be used as the output operand for a move insn. */
-
-int
-out_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- rtx orig_op = op;
-
- if (! general_operand (op, mode))
- return 0;
-
- while (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- if (GET_CODE (op) == REG)
- return (gpc_reg_operand (orig_op, mode)
- || spec_reg_operand (orig_op, mode)
- || (GET_MODE_CLASS (mode) == MODE_FLOAT
- && accum_reg_operand (orig_op, mode)));
-
- else if (GET_CODE (op) == MEM)
- return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);
- else
- return 0;
-}
-
-/* Return 1 if OP is an item in memory, given that we are in reload. */
-
-int
-reload_memory_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- int regno = true_regnum (op);
-
- return (! CONSTANT_P (op)
- && (regno == -1
- || (GET_CODE (op) == REG
- && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
-}
-
-/* Given an object for which reload_memory_operand is true, return the address
- of the operand, taking into account anything that reload may do. */
-
-rtx
-a29k_get_reloaded_address (op)
- rtx op;
-{
- if (GET_CODE (op) == SUBREG)
- {
- if (SUBREG_WORD (op) != 0)
- abort ();
-
- op = SUBREG_REG (op);
- }
-
- if (GET_CODE (op) == REG)
- op = reg_equiv_mem[REGNO (op)];
-
- return find_replacement (&XEXP (op, 0));
-}
-
-/* Subfunction of the following function. Update the flags of any MEM
- found in part of X. */
-
-static void
-a29k_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
- rtx x;
- int in_struct_p, volatile_p, unchanging_p;
-{
- int i;
-
- switch (GET_CODE (x))
- {
- case SEQUENCE:
- case PARALLEL:
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- a29k_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p,
- unchanging_p);
- break;
-
- case INSN:
- a29k_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p,
- unchanging_p);
- break;
-
- case SET:
- a29k_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p,
- unchanging_p);
- a29k_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, unchanging_p);
- break;
-
- case MEM:
- MEM_IN_STRUCT_P (x) = in_struct_p;
- MEM_VOLATILE_P (x) = volatile_p;
- RTX_UNCHANGING_P (x) = unchanging_p;
- break;
- }
-}
-
-/* Given INSN, which is either an INSN or a SEQUENCE generated to
- perform a memory operation, look for any MEMs in either a SET_DEST or
- a SET_SRC and copy the in-struct, unchanging, and volatile flags from
- REF into each of the MEMs found. If REF is not a MEM, don't do
- anything. */
-
-void
-a29k_set_memflags (insn, ref)
- rtx insn;
- rtx ref;
-{
- /* Note that it is always safe to get these flags, though they won't
- be what we think if REF is not a MEM. */
- int in_struct_p = MEM_IN_STRUCT_P (ref);
- int volatile_p = MEM_VOLATILE_P (ref);
- int unchanging_p = RTX_UNCHANGING_P (ref);
-
- if (GET_CODE (ref) != MEM
- || (! in_struct_p && ! volatile_p && ! unchanging_p))
- return;
-
- a29k_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p);
-}
-
-/* Return 1 if OP is a comparison operator that we have in floating-point. */
-
-int
-fp_comparison_operator (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return ((mode == VOIDmode || mode == GET_MODE (op))
- && (GET_CODE (op) == EQ || GET_CODE (op) == GT ||
- GET_CODE (op) == GE));
-}
-
-/* Return 1 if OP is a valid branch comparison. */
-
-int
-branch_operator (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return ((mode == VOIDmode || mode == GET_MODE (op))
- && (GET_CODE (op) == GE || GET_CODE (op) == LT));
-}
-
-/* Return 1 if OP is a load multiple operation. It is known to be a
- PARALLEL and the first three sections will be tested. */
-
-int
-load_multiple_operation (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- int count = XVECLEN (op, 0) - 2;
- int dest_regno;
- rtx src_addr;
- int i;
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
- return 0;
-
- dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
- src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
-
- for (i = 1; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i + 2);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_DEST (elt)) != REG
- || GET_MODE (SET_DEST (elt)) != SImode
- || REGNO (SET_DEST (elt)) != dest_regno + i
- || GET_CODE (SET_SRC (elt)) != MEM
- || GET_MODE (SET_SRC (elt)) != SImode
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
- || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
- || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
- return 0;
- }
-
- return 1;
-}
-
-/* Similar, but tests for store multiple. */
-
-int
-store_multiple_operation (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- int num_special = TARGET_NO_STOREM_BUG ? 2 : 1;
- int count = XVECLEN (op, 0) - num_special;
- int src_regno;
- rtx dest_addr;
- int i;
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
- return 0;
-
- src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
- dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
-
- for (i = 1; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i + num_special);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_SRC (elt)) != REG
- || GET_MODE (SET_SRC (elt)) != SImode
- || REGNO (SET_SRC (elt)) != src_regno + i
- || GET_CODE (SET_DEST (elt)) != MEM
- || GET_MODE (SET_DEST (elt)) != SImode
- || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
- || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
- || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
- return 0;
- }
-
- return 1;
-}
-
-/* Given a special register REG and MASK, a value being masked against a
- quantity to which the special register is set, return 1 if the masking
- operation is built-in to the setting of that special register. */
-
-int
-masks_bits_for_special (reg, mask)
- rtx reg;
- rtx mask;
-{
- int needed_mask_value;
-
- if (GET_CODE (reg) != REG || GET_CODE (mask) != CONST_INT)
- abort ();
-
- switch (REGNO (reg))
- {
- case R_BP:
- case R_INT:
- needed_mask_value = 3;
- break;
-
- case R_FC:
- needed_mask_value = 31;
- break;
-
- case R_CR:
- case R_LRU:
- needed_mask_value = 255;
- break;
-
- case R_FPE:
- needed_mask_value = 511;
- break;
-
- case R_MMU:
- needed_mask_value = 0x3ff;
- break;
-
- case R_OPS:
- case R_CPS:
- case R_RBP:
- case R_FPS:
- needed_mask_value = 0xffff;
- break;
-
- case R_VAB:
- needed_mask_value = 0xffff0000;
- break;
-
- case R_Q:
- case R_CFG:
- case R_CHA:
- case R_CHD:
- case R_CHC:
- case R_TMC:
- case R_TMR:
- case R_PC0:
- case R_PC1:
- case R_PC2:
- return 0;
-
- default:
- abort ();
- }
-
- return (INTVAL (mask) & ~ needed_mask_value) == 0;
-}
-
-/* Return nonzero if this label is that of the return point, but there is
- a non-null epilogue. */
-
-int
-epilogue_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return next_active_insn (op) == 0 && a29k_first_epilogue_insn != 0;
-}
-
-/* Return the register class of a scratch register needed to copy IN into
- or out of a register in CLASS in MODE. If it can be done directly,
- NO_REGS is returned. */
-
-enum reg_class
-secondary_reload_class (class, mode, in)
- enum reg_class class;
- enum machine_mode mode;
- rtx in;
-{
- int regno = -1;
- enum rtx_code code = GET_CODE (in);
-
- if (! CONSTANT_P (in))
- {
- regno = true_regnum (in);
-
- /* A pseudo is the same as memory. */
- if (regno == -1 || regno >= FIRST_PSEUDO_REGISTER)
- code = MEM;
- }
-
- /* If we are transferring between memory and a multi-word mode, we need
- CR. */
-
- if (code == MEM && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
- return CR_REGS;
-
- /* If between memory and a mode smaller than a word without DW being
- enabled, we need BP. */
-
- if (code == MEM && ! TARGET_DW_ENABLE
- && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
- return BP_REGS;
-
- /* Otherwise, we can place anything into GENERAL_REGS and can put
- GENERAL_REGS into anything. */
- if (class == GENERAL_REGS
- || (regno != -1
- && (regno < R_BP
- || (regno >= R_KR (0) && regno <= R_KR (31)))))
- return NO_REGS;
-
- /* We can place 16-bit constants into a special register. */
- if (code == CONST_INT
- && (GET_MODE_BITSIZE (mode) <= 16 || (unsigned) INTVAL (in) <= 65535)
- && (class == BP_REGS || class == Q_REGS || class == SPECIAL_REGS))
- return NO_REGS;
-
- /* Otherwise, we need GENERAL_REGS. */
- return GENERAL_REGS;
-}
-
-/* START is the zero-based incoming argument register index used (0 is 160,
- i.e., the first incoming argument register) and COUNT is the number used.
-
- Mark the corresponding incoming registers as neither fixed nor call used.
- For each register used for incoming arguments, we have one less local
- register that can be used. So also mark some high-numbered registers as
- fixed.
-
- Return the first register number to use for the argument. */
-
-int
-incoming_reg (start, count)
- int start;
- int count;
-{
- int i;
-
- /* We only use 16 argument registers, so truncate at the end of the
- area. */
- if (start + count > 16)
- count = 16 - start;
-
- if (! TARGET_NO_REUSE_ARGS)
- /* Mark all the used registers as not fixed and saved over calls. */
- for (i = R_AR (start); i < R_AR (start + count); i++)
- {
- fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 0;
- CLEAR_HARD_REG_BIT (fixed_reg_set, i);
- CLEAR_HARD_REG_BIT (call_used_reg_set, i);
- CLEAR_HARD_REG_BIT (call_fixed_reg_set, i);
- }
-
- /* Shorten the maximum size of the frame.
- Remember that R_AR(-1,-2) are place holders for the caller's lr0,lr1.
- Make sure to keep the frame rounded to an even boundary. Rounding up
- to an 8 byte boundary will use a slot. Otherwise a frame with 121 local
- regs and 5 arguments will overrun the stack (121+1 + 5 + 2 > 128). */
- /* ??? An alternative would be to never allocate one reg. */
- for (i = (R_AR (0) - 2 - start - count) & ~1; i < R_AR (0) - 2 - start; i++)
- {
- fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;
- SET_HARD_REG_BIT (fixed_reg_set, i);
- SET_HARD_REG_BIT (call_used_reg_set, i);
- SET_HARD_REG_BIT (call_fixed_reg_set, i);
- }
-
- return R_AR (start);
-}
-
-/* Add CLOBBERs to CALL_INSN_FUNCTION_USAGE chain of INSN indicating
- that LR2 up to, but not including, OP are clobbered. If OP is
- zero, indicate all parameter registers are clobbered. */
-
-void
-a29k_clobbers_to (insn, op)
- rtx insn;
- rtx op;
-{
- int i;
- int high_regno;
-
- if (op == 0)
- high_regno = R_LR (18);
- else if (GET_CODE (op) != REG || REGNO (op) < R_LR (0)
- || REGNO (op) > R_LR (18))
- abort ();
- else
- high_regno = REGNO (op);
-
- for (i = R_LR (2); i < high_regno; i++)
- CALL_INSN_FUNCTION_USAGE (insn)
- = gen_rtx (EXPR_LIST, VOIDmode,
- gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, i)),
- CALL_INSN_FUNCTION_USAGE (insn));
-}
-
-/* These routines are used in finding insns to fill delay slots in the
- epilogue. */
-
-/* Return 1 if the current function will adjust the register stack. */
-
-int
-needs_regstack_p ()
-{
- int i;
- rtx insn;
-
- if (frame_pointer_needed)
- return 1;
-
- /* If any local register is used, we need to adjust the regstack. */
- for (i = R_LR (127); i >= R_LR (0); i --)
- if (regs_ever_live[i])
- return 1;
-
- /* We need a register stack if we make any calls. */
- for (insn = get_insns (); insn; insn = next_insn (insn))
- if (GET_CODE (insn) == CALL_INSN
- || (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SEQUENCE
- && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
- return 1;
-
- /* Otherwise, we don't. */
- return 0;
-}
-
-/* Return 1 if X uses a local register. */
-
-int
-uses_local_reg_p (x)
- rtx x;
-{
- char *fmt;
- int i, j;
-
- switch (GET_CODE (x))
- {
- case REG:
- return REGNO (x) >= R_LR (0) && REGNO (x) <= R_FP;
-
- case CONST_INT:
- case CONST:
- case PC:
- case CC0:
- case LABEL_REF:
- case SYMBOL_REF:
- return 0;
- }
-
- fmt = GET_RTX_FORMAT (GET_CODE (x));
- for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (uses_local_reg_p (XEXP (x, i)))
- return 1;
- }
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (uses_local_reg_p (XVECEXP (x, i, j)))
- return 1;
- }
- }
-
- return 0;
-}
-
-/* Returns 1 if this function is known to have a null epilogue. */
-
-int
-null_epilogue ()
-{
- return (reload_completed && ! needs_regstack_p ()
- && get_frame_size () == 0
- && current_function_pretend_args_size == 0);
-}
-
-/* Write out the assembler form of an operand. Recognize the following
- special options:
-
- %N means write the low-order 8 bits of the negative of the constant
- %Q means write a QImode operand (truncate constants to 8 bits)
- %M means write the low-order 16 bits of the constant
- %m means write the low-order 16 bits shifted left 16 bits
- %C means write the low-order 8 bits of the complement of the constant
- %b means write `f' is this is a reversed condition, `t' otherwise
- %B means write `t' is this is a reversed condition, `f' otherwise
- %J means write the 29k opcode part for a comparison operation
- %e means write the label with an extra `X' is this is the epilogue
- otherwise the normal label name
- %E means write nothing if this insn has a delay slot,
- a nop unless this is the epilogue label, in which case
- write the first epilogue insn
- %F means write just the normal operand if the insn has a delay slot;
- otherwise, this is a recursive call so output the
- symbol + 4 and write the first prologue insn in the
- delay slot.
- %L means write the register number plus one ("low order" register)
- or the low-order part of a multi-word constant
- %O means write the register number plus two
- %P means write the register number plus three ("low order" of TImode)
- %S means write the number of words in the mode of the operand,
- minus one (for CR)
- %V means write the number of elements in a PARALLEL minus 1
- %# means write nothing if we have a delay slot, "\n\tnop" otherwise
- %* means write the register name for TPC. */
-
-void
-print_operand (file, x, code)
- FILE *file;
- rtx x;
- char code;
-{
- char buf[100];
-
- /* These macros test for integers and extract the low-order bits. */
-#define INT_P(X) \
-((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE) \
- && GET_MODE (X) == VOIDmode)
-
-#define INT_LOWPART(X) \
- (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
-
- switch (code)
- {
- case 'Q':
- if (GET_CODE (x) == REG)
- break;
- else if (! INT_P (x))
- output_operand_lossage ("invalid %%Q value");
- fprintf (file, "%d", INT_LOWPART (x) & 0xff);
- return;
-
- case 'C':
- if (! INT_P (x))
- output_operand_lossage ("invalid %%C value");
- fprintf (file, "%d", (~ INT_LOWPART (x)) & 0xff);
- return;
-
- case 'N':
- if (! INT_P (x))
- output_operand_lossage ("invalid %%N value");
- fprintf (file, "%d", (- INT_LOWPART (x)) & 0xff);
- return;
-
- case 'M':
- if (! INT_P (x))
- output_operand_lossage ("invalid %%M value");
- fprintf (file, "%d", INT_LOWPART (x) & 0xffff);
- return;
-
- case 'm':
- if (! INT_P (x))
- output_operand_lossage ("invalid %%m value");
- fprintf (file, "%d", (INT_LOWPART (x) & 0xffff) << 16);
- return;
-
- case 'b':
- if (GET_CODE (x) == GE)
- fprintf (file, "f");
- else
- fprintf (file, "t");
- return;
-
- case 'B':
- if (GET_CODE (x) == GE)
- fprintf (file, "t");
- else
- fprintf (file, "f");
- return;
-
- case 'J':
- /* It so happens that the RTX names for the conditions are the same as
- the 29k's insns except for "ne", which requires "neq". */
- fprintf (file, GET_RTX_NAME (GET_CODE (x)));
- if (GET_CODE (x) == NE)
- fprintf (file, "q");
- return;
-
- case 'e':
- if (optimize && flag_delayed_branch
- && a29k_last_prologue_insn == 0 && epilogue_operand (x, VOIDmode)
- && dbr_sequence_length () == 0)
- {
- /* We need to output the label number of the last label in the
- function, which is not necessarily X since there might be
- a USE insn in between. First go forward to the last insn, then
- back up to a label. */
- while (NEXT_INSN (x) != 0)
- x = NEXT_INSN (x);
-
- while (GET_CODE (x) != CODE_LABEL)
- x = PREV_INSN (x);
-
- ASM_GENERATE_INTERNAL_LABEL (buf, "LX", CODE_LABEL_NUMBER (x));
- assemble_name (file, buf);
- }
- else
- output_asm_label (x);
- return;
-
- case 'E':
- if (dbr_sequence_length ())
- ;
- else if (a29k_last_prologue_insn)
- {
- fprintf (file, "\n\t%s", a29k_last_prologue_insn);
- a29k_last_prologue_insn = 0;
- }
- else if (optimize && flag_delayed_branch
- && epilogue_operand (x, VOIDmode))
- {
- fprintf (file, "\n\t%s", a29k_first_epilogue_insn);
- a29k_first_epilogue_insn_used = 1;
- }
- else
- fprintf (file, "\n\tnop");
- return;
-
- case 'F':
- output_addr_const (file, x);
- if (dbr_sequence_length () == 0)
- {
- /* If this doesn't have its delay slot filled, see if we need to
- put the last insn of the prolog in it. If not, see if this is
- a recursive call. If so, we can put the first insn of its
- prolog in the delay slot. Otherwise, write a nop. */
- if (a29k_last_prologue_insn)
- {
- fprintf (file, "\n\t%s", a29k_last_prologue_insn);
- a29k_last_prologue_insn = 0;
- }
- else if (GET_CODE (x) == SYMBOL_REF
- && ! strcmp (XSTR (x, 0), current_function_name))
- fprintf (file, "+4\n\t%s,%d",
- a29k_regstack_size >= 64 ? "const gr121" : "sub gr1,gr1",
- a29k_regstack_size * 4);
- else
- fprintf (file, "\n\tnop");
- }
- return;
-
- case 'L':
- if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
- {
- union real_extract u;
-
- bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
- fprintf (file, "$double1(%.20e)", u.d);
- }
- else if (GET_CODE (x) == REG)
- fprintf (file, "%s", reg_names[REGNO (x) + 1]);
- else
- output_operand_lossage ("invalid %%L value");
- return;
-
- case 'O':
- if (GET_CODE (x) != REG)
- output_operand_lossage ("invalid %%O value");
- fprintf (file, "%s", reg_names[REGNO (x) + 2]);
- return;
-
- case 'P':
- if (GET_CODE (x) != REG)
- output_operand_lossage ("invalid %%P value");
- fprintf (file, "%s", reg_names[REGNO (x) + 3]);
- return;
-
- case 'S':
- fprintf (file, "%d", (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD)-1);
- return;
-
- case 'V':
- if (GET_CODE (x) != PARALLEL)
- output_operand_lossage ("invalid %%V value");
- fprintf (file, "%d", XVECLEN (x, 0) - 2);
- return;
-
- case '#':
- if (dbr_sequence_length () == 0)
- {
- if (a29k_last_prologue_insn)
- {
- fprintf (file, "\n\t%s", a29k_last_prologue_insn);
- a29k_last_prologue_insn = 0;
- }
- else
- fprintf (file, "\n\tnop");
- }
- return;
-
- case '*':
- fprintf (file, "%s", reg_names [R_TPC]);
- return;
- }
-
- if (GET_CODE (x) == REG)
- fprintf (file, "%s", reg_names [REGNO (x)]);
-
- else if (GET_CODE (x) == MEM)
- output_address (XEXP (x, 0));
-
- else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == SUBREG
- && GET_CODE (SUBREG_REG (XEXP (x, 0))) == CONST_DOUBLE)
- {
- union real_extract u;
-
- if (GET_MODE (SUBREG_REG (XEXP (x, 0))) == SFmode)
- fprintf (file, "$float");
- else
- fprintf (file, "$double%d", SUBREG_WORD (XEXP (x, 0)));
- bcopy ((char *) &CONST_DOUBLE_LOW (SUBREG_REG (XEXP (x, 0))),
- (char *) &u, sizeof u);
- fprintf (file, "(%.20e)", u.d);
- }
-
- else if (GET_CODE (x) == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
- {
- union real_extract u;
-
- bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
- fprintf (file, "$%s(%.20e)",
- GET_MODE (x) == SFmode ? "float" : "double0", u.d);
- }
-
- else
- output_addr_const (file, x);
-}
-
-/* This page contains routines to output function prolog and epilog code. */
-
-/* Output function prolog code to file FILE. Memory stack size is SIZE.
-
- Also sets register names for incoming arguments and frame pointer. */
-
-void
-output_prolog (file, size)
- FILE *file;
- int size;
-{
- int makes_calls = 0;
- int arg_count = 0;
- rtx insn;
- int i;
- unsigned int tag_word;
-
- /* See if we make any calls. We need to set lr1 if so. */
- for (insn = get_insns (); insn; insn = next_insn (insn))
- if (GET_CODE (insn) == CALL_INSN
- || (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SEQUENCE
- && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
- {
- makes_calls = 1;
- break;
- }
-
- /* Find the highest local register used. */
- for (i = R_LR (127); i >= R_LR (0); i--)
- if (regs_ever_live[i])
- break;
-
- a29k_regstack_size = i - (R_LR (0) - 1);
-
- /* If calling routines, ensure we count lr0 & lr1. */
- if (makes_calls && a29k_regstack_size < 2)
- a29k_regstack_size = 2;
-
- /* Count frame pointer and align to 8 byte boundary (even number of
- registers). */
- a29k_regstack_size += frame_pointer_needed;
- if (a29k_regstack_size & 1) a29k_regstack_size++;
-
- /* See how many incoming arguments we have in registers. */
- for (i = R_AR (0); i < R_AR (16); i++)
- if (! fixed_regs[i])
- arg_count++;
-
- /* The argument count includes the caller's lr0 and lr1. */
- arg_count += 2;
-
- /* Set the names and numbers of the frame pointer and incoming argument
- registers. */
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- a29k_debug_reg_map[i] = i;
-
- reg_names[FRAME_POINTER_REGNUM] = reg_names[R_LR (a29k_regstack_size - 1)];
- a29k_debug_reg_map[FRAME_POINTER_REGNUM] = R_LR (a29k_regstack_size - 1);
-
- for (i = 0; i < 16; i++)
- {
- reg_names[R_AR (i)] = reg_names[R_LR (a29k_regstack_size + i + 2)];
- a29k_debug_reg_map[R_AR (i)] = R_LR (a29k_regstack_size + i + 2);
- }
-
- /* If using kernel register map, swap numbers for kernel and user
- registers. */
- if (TARGET_KERNEL_REGISTERS)
- for (i = 0; i < 32; i++)
- {
- int tem = a29k_debug_reg_map[i];
- a29k_debug_reg_map[i] = a29k_debug_reg_map[R_KR (i)];
- a29k_debug_reg_map[R_KR (i)] = tem;
- }
-
- /* Compute memory stack size. Add in number of bytes that the we should
- push and pretend the caller did and the size of outgoing arguments.
- Then round to a doubleword boundary. */
- size += (current_function_pretend_args_size
- + current_function_outgoing_args_size);
- size = (size + 7) & ~7;
-
- /* Write header words. See if one or two word form. */
- tag_word = (frame_pointer_needed ? 0x400000 : 0) + (arg_count << 16);
-
- if (size / 8 > 0xff)
- fprintf (file, "\t.word %d, 0x%0x\n", (size / 8) << 2,
- 0x800000 + tag_word);
- else
- fprintf (file, "\t.word 0x%0x\n", tag_word + ((size / 8) << 3));
-
- /* Define the function name. */
- assemble_name (file, a29k_function_name);
- fprintf (file, ":\n");
-
- /* Push the register stack by the proper amount. There are two possible
- ways to do this. */
- if (a29k_regstack_size >= 256/4)
- fprintf (file, "\tconst %s,%d\n\tsub gr1,gr1,%s\n",
- reg_names[R_TAV], a29k_regstack_size * 4, reg_names[R_TAV]);
- else if (a29k_regstack_size)
- fprintf (file, "\tsub gr1,gr1,%d\n", a29k_regstack_size * 4);
-
- /* Test that the registers are available. */
- if (a29k_regstack_size)
- fprintf (file, "\tasgeu V_%sSPILL,gr1,%s\n",
- TARGET_KERNEL_REGISTERS ? "K" : "", reg_names[R_RAB]);
-
- /* Set up frame pointer, if one is needed. */
- if (frame_pointer_needed)
- fprintf (file, "\tsll %s,%s,0\n", reg_names[FRAME_POINTER_REGNUM],
- reg_names[R_MSP]);
-
- /* Make room for any frame space. There are three ways to do this. */
- if (size >= 256)
- {
- fprintf (file, "\tconst %s,%d\n", reg_names[R_TAV], size);
- if (size >= 65536)
- fprintf (file, "\tconsth %s,%d\n", reg_names[R_TAV], size);
- if (TARGET_STACK_CHECK)
- fprintf (file, "\tcall %s,__msp_check\n", reg_names[R_TPC]);
- fprintf (file, "\tsub %s,%s,%s\n",
- reg_names[R_MSP], reg_names[R_MSP], reg_names[R_TAV]);
- }
- else if (size)
- {
- if (TARGET_STACK_CHECK)
- fprintf (file, "\tcall %s,__msp_check\n", reg_names[R_TPC]);
- fprintf (file, "\tsub %s,%s,%d\n",
- reg_names[R_MSP], reg_names[R_MSP], size);
- }
-
- /* If this routine will make calls, set lr1. If we see an insn that
- can use a delay slot before a call or jump, save this insn for that
- slot (this condition is equivalent to seeing if we have an insn that
- needs delay slots before an insn that has a filled delay slot). */
- a29k_last_prologue_insn = 0;
- if (makes_calls)
- {
- i = (a29k_regstack_size + arg_count) * 4;
- if (i >= 256)
- fprintf (file, "\tconst %s,%d\n\tadd lr1,gr1,%s\n",
- reg_names[R_TAV], i, reg_names[R_TAV]);
- else
- {
- if (optimize && flag_delayed_branch)
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == CODE_LABEL
- || (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SEQUENCE))
- break;
-
- if (GET_CODE (insn) == NOTE
- || (GET_CODE (insn) == INSN
- && (GET_CODE (PATTERN (insn)) == USE
- || GET_CODE (PATTERN (insn)) == CLOBBER)))
- continue;
-
- if (num_delay_slots (insn) > 0)
- {
- a29k_last_prologue_insn = (char *) oballoc (100);
- sprintf (a29k_last_prologue_insn, "add lr1,gr1,%d", i);
- break;
- }
- }
-
- if (a29k_last_prologue_insn == 0)
- fprintf (file, "\tadd lr1,gr1,%d\n", i);
- }
- }
-
- /* Compute the first insn of the epilogue. */
- a29k_first_epilogue_insn_used = 0;
-
- if (size == 0 && a29k_regstack_size == 0 && ! frame_pointer_needed)
- a29k_first_epilogue_insn = 0;
- else
- a29k_first_epilogue_insn = (char *) oballoc (100);
-
- if (frame_pointer_needed)
- sprintf (a29k_first_epilogue_insn, "sll %s,%s,0",
- reg_names[R_MSP], reg_names[FRAME_POINTER_REGNUM]);
- else if (a29k_regstack_size)
- {
- if (a29k_regstack_size >= 256 / 4)
- sprintf (a29k_first_epilogue_insn, "const %s,%d",
- reg_names[R_TAV], a29k_regstack_size * 4);
- else
- sprintf (a29k_first_epilogue_insn, "add gr1,gr1,%d",
- a29k_regstack_size * 4);
- }
- else if (size)
- {
- if (size >= 256)
- sprintf (a29k_first_epilogue_insn, "const %s,%d",
- reg_names[R_TAV], size);
- else
- sprintf (a29k_first_epilogue_insn, "add %s,%s,%d",
- reg_names[R_MSP], reg_names[R_MSP], size);
- }
-}
-
-/* Call this after writing what might be the first instruction of the
- epilogue. If that first insn was used in a delay slot, an intermediate
- label is written. */
-
-static void
-check_epilogue_internal_label (file)
- FILE *file;
-{
- rtx insn;
-
- if (! a29k_first_epilogue_insn_used)
- return;
-
- for (insn = get_last_insn ();
- GET_CODE (insn) != CODE_LABEL;
- insn = PREV_INSN (insn))
- ;
-
- ASM_OUTPUT_INTERNAL_LABEL (file, "LX", CODE_LABEL_NUMBER (insn));
- a29k_first_epilogue_insn_used = 0;
-}
-
-/* Output the epilog of the last procedure to file FILE. SIZE is the memory
- stack size. The register stack size is in the variable
- A29K_REGSTACK_SIZE. */
-
-void
-output_epilog (file, size)
- FILE *file;
- int size;
-{
- rtx insn;
- int locals_unavailable = 0; /* True until after first insn
- after gr1 update. */
-
- /* If we hit a BARRIER before a real insn or CODE_LABEL, we don't
- need to do anything because we are never jumped to. */
- insn = get_last_insn ();
- if (GET_CODE (insn) == NOTE)
- insn = prev_nonnote_insn (insn);
-
- if (insn && GET_CODE (insn) == BARRIER)
- return;
-
- /* If a frame pointer was needed we must restore the memory stack pointer
- before adjusting the register stack. */
- if (frame_pointer_needed)
- {
- fprintf (file, "\tsll %s,%s,0\n",
- reg_names[R_MSP], reg_names[FRAME_POINTER_REGNUM]);
- check_epilogue_internal_label (file);
- }
-
- /* Restore the register stack. There are two ways to do this. */
- if (a29k_regstack_size)
- {
- if (a29k_regstack_size >= 256/4)
- {
- fprintf (file, "\tconst %s,%d\n",
- reg_names[R_TAV], a29k_regstack_size * 4);
- check_epilogue_internal_label (file);
- fprintf (file, "\tadd gr1,gr1,%s\n", reg_names[R_TAV]);
- }
- else
- {
- fprintf (file, "\tadd gr1,gr1,%d\n", a29k_regstack_size * 4);
- check_epilogue_internal_label (file);
- }
- locals_unavailable = 1;
- }
-
- /* Restore the memory stack pointer if there is no frame pointer.
- Adjust the size to include any pretend arguments and pushed
- arguments and round to doubleword boundary. */
- size += (current_function_pretend_args_size
- + current_function_outgoing_args_size);
- size = (size + 7) & ~7;
-
- if (size && ! frame_pointer_needed)
- {
- if (size >= 256)
- {
- fprintf (file, "\tconst %s,%d\n", reg_names[R_TAV], size);
- check_epilogue_internal_label (file);
- locals_unavailable = 0;
- if (size >= 65536)
- fprintf (file, "\tconsth %s,%d\n", reg_names[R_TAV], size);
- fprintf (file, "\tadd %s,%s,%s\n",
- reg_names[R_MSP], reg_names[R_MSP], reg_names[R_TAV]);
- }
- else
- {
- fprintf (file, "\tadd %s,%s,%d\n",
- reg_names[R_MSP], reg_names[R_MSP], size);
- check_epilogue_internal_label (file);
- locals_unavailable = 0;
- }
- }
-
- if (locals_unavailable)
- {
- /* If we have an insn for this delay slot, write it. */
- if (current_function_epilogue_delay_list)
- final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
- file, 1, -2, 1);
- else
- fprintf (file, "\tnop\n");
- }
-
- fprintf (file, "\tjmpi lr0\n");
- if (a29k_regstack_size)
- fprintf (file, "\tasleu V_%sFILL,lr1,%s\n",
- TARGET_KERNEL_REGISTERS ? "K" : "", reg_names[R_RFB]);
- else if (current_function_epilogue_delay_list)
- final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
- file, 1, -2, 1);
- else
- fprintf (file, "\tnop\n");
-}