aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Wilson <wilson@gcc.gnu.org>1996-01-18 14:41:00 -0800
committerJim Wilson <wilson@gcc.gnu.org>1996-01-18 14:41:00 -0800
commit1a95a9637341ec6541d8bb05508d8b35e0f16c03 (patch)
tree84bf9efa55ad53ce50f29919daabec4ccd35e43f
parent5c3ea8054637ec397cdc68b22f3c06ce7920a205 (diff)
downloadgcc-1a95a9637341ec6541d8bb05508d8b35e0f16c03.zip
gcc-1a95a9637341ec6541d8bb05508d8b35e0f16c03.tar.gz
gcc-1a95a9637341ec6541d8bb05508d8b35e0f16c03.tar.bz2
(ctype.h): Delete.
(regno_reg_class, reg_class_from_letter, prepare_scc_operands, broken_move, push, pop, push_regs, calc_live_regs, sh_expand_prologue, sh_expand_epilogue, initial_elimination_offset, arith_reg_operand): Add SH3e support. (sh_builtin_saveregs, fp_zero_operand, fp_one_operand): New functions. (sh_function_arg, sh_function_arg_partial_nregs): Delete. From-SVN: r11068
-rw-r--r--gcc/config/sh/sh.c234
1 files changed, 154 insertions, 80 deletions
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 81125b3..1a9cda9 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -23,7 +23,6 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <ctype.h>
#include <stdio.h>
#include "rtl.h"
@@ -85,7 +84,11 @@ int regno_reg_class[FIRST_PSEUDO_REGISTER] =
GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
GENERAL_REGS, PR_REGS, T_REGS, NO_REGS,
- MAC_REGS, MAC_REGS,
+ MAC_REGS, MAC_REGS, FPUL_REGS, NO_REGS,
+ FP0_REGS,FP_REGS, FP_REGS, FP_REGS,
+ FP_REGS, FP_REGS, FP_REGS, FP_REGS,
+ FP_REGS, FP_REGS, FP_REGS, FP_REGS,
+ FP_REGS, FP_REGS, FP_REGS, FP_REGS,
};
/* Provide reg_class from a letter such as appears in the machine
@@ -94,12 +97,12 @@ int regno_reg_class[FIRST_PSEUDO_REGISTER] =
enum reg_class reg_class_from_letter[] =
{
/* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS,
- /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
+ /* e */ NO_REGS, /* f */ FP_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
/* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
/* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
/* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS,
- /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS,
- /* y */ NO_REGS, /* z */ R0_REGS
+ /* u */ NO_REGS, /* v */ NO_REGS, /* w */ FP0_REGS, /* x */ MAC_REGS,
+ /* y */ FPUL_REGS, /* z */ R0_REGS
};
/* Print the operand address in x to the stream. */
@@ -367,6 +370,8 @@ prepare_scc_operands (code)
|| code == GTU || code == GEU || code == LTU || code == LEU))
sh_compare_op1 = force_reg (mode, sh_compare_op1);
+ /* ??? This should be `mode' not `SImode' in the compare, but that would
+ require fixing the branch patterns too. */
emit_insn (gen_rtx (SET, VOIDmode, t_reg,
gen_rtx (code, SImode, sh_compare_op0,
sh_compare_op1)));
@@ -1212,6 +1217,12 @@ broken_move (insn)
order bits end up as. */
&& GET_MODE (SET_DEST (PATTERN (insn))) != QImode
&& CONSTANT_P (SET_SRC (PATTERN (insn)))
+ && ! (GET_CODE (SET_SRC (PATTERN (insn))) == CONST_DOUBLE
+ && (fp_zero_operand (SET_SRC (PATTERN (insn)))
+ || fp_one_operand (SET_SRC (PATTERN (insn))))
+ && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+ && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FP_REG
+ && REGNO (SET_DEST (PATTERN (insn))) <= LAST_FP_REG)
&& (GET_CODE (SET_SRC (PATTERN (insn))) != CONST_INT
|| ! CONST_OK_FOR_I (INTVAL (SET_SRC (PATTERN (insn))))))
return 1;
@@ -1828,7 +1839,12 @@ push (rn)
int rn;
{
rtx x;
- x = emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
+ if ((rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
+ || rn == FPUL_REG)
+ x = emit_insn (gen_push_e (gen_rtx (REG, SFmode, rn)));
+ else
+ x = emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
+
REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC,
gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0);
}
@@ -1840,7 +1856,12 @@ pop (rn)
int rn;
{
rtx x;
- x = emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
+ if ((rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
+ || rn == FPUL_REG)
+ x = emit_insn (gen_pop_e (gen_rtx (REG, SFmode, rn)));
+ else
+ x = emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
+
REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC,
gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0);
}
@@ -1849,14 +1870,17 @@ pop (rn)
the number of bytes the insns take. */
static void
-push_regs (mask)
- int mask;
+push_regs (mask, mask2)
+ int mask, mask2;
{
int i;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ for (i = 0; i < 32; i++)
if (mask & (1 << i))
push (i);
+ for (i = 32; i < FIRST_PSEUDO_REGISTER; i++)
+ if (mask2 & (1 << (i - 32)))
+ push (i);
}
/* Work out the registers which need to be saved, both as a mask and a
@@ -1867,27 +1891,29 @@ push_regs (mask)
make sure that all the regs it clobbers are safe too. */
static int
-calc_live_regs (count_ptr)
+calc_live_regs (count_ptr, live_regs_mask2)
int *count_ptr;
+ int *live_regs_mask2;
{
int reg;
int live_regs_mask = 0;
int count = 0;
+ *live_regs_mask2 = 0;
for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
{
if (pragma_interrupt && ! pragma_trapa)
{
- /* Normally, we must save all the regs ever live.
- If pragma_nosave_low_regs, then don't save any of the
- registers which are banked on the SH3. */
+ /* Need to save all the regs ever live. */
if ((regs_ever_live[reg]
|| (call_used_regs[reg] && regs_ever_live[PR_REG]))
&& reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
- && reg != T_REG && reg != GBR_REG
- && ! (sh_cpu == CPU_SH3 && pragma_nosave_low_regs && reg < 8))
+ && reg != T_REG && reg != GBR_REG)
{
- live_regs_mask |= 1 << reg;
+ if (reg >= 32)
+ *live_regs_mask2 |= 1 << (reg - 32);
+ else
+ live_regs_mask |= 1 << reg;
count++;
}
}
@@ -1896,7 +1922,10 @@ calc_live_regs (count_ptr)
/* Only push those regs which are used and need to be saved. */
if (regs_ever_live[reg] && ! call_used_regs[reg])
{
- live_regs_mask |= (1 << reg);
+ if (reg >= 32)
+ *live_regs_mask2 |= 1 << (reg - 32);
+ else
+ live_regs_mask |= (1 << reg);
count++;
}
}
@@ -1913,7 +1942,8 @@ sh_expand_prologue ()
{
int live_regs_mask;
int d, i;
- live_regs_mask = calc_live_regs (&d);
+ int live_regs_mask2;
+ live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
/* We have pretend args if we had an object sent partially in registers
and partially on the stack, e.g. a large structure. */
@@ -1922,23 +1952,30 @@ sh_expand_prologue ()
extra_push = 0;
/* This is set by SETUP_VARARGS to indicate that this is a varargs
- routine. Clear it here so that the next function isn't affected. */
+ routine. Clear it here so that the next function isn't affected. */
if (current_function_anonymous_args)
{
current_function_anonymous_args = 0;
- /* Push arg regs as if they'd been provided by caller in stack. */
- for (i = 0; i < NPARM_REGS; i++)
- {
- int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
- if (i > (NPARM_REGS - current_function_args_info
- - current_function_varargs))
- break;
- push (rn);
- extra_push += 4;
- }
+ /* This is not used by the SH3E calling convention */
+ if (!TARGET_SH3E)
+ {
+ /* Push arg regs as if they'd been provided by caller in stack. */
+ for (i = 0; i < NPARM_REGS(SImode); i++)
+ {
+ int rn = NPARM_REGS(SImode) + FIRST_PARM_REG - i - 1;
+ if (i > (NPARM_REGS(SImode)
+ - current_function_args_info.arg_count[(int) SH_ARG_INT]
+ - current_function_varargs))
+ break;
+ push (rn);
+ extra_push += 4;
+ }
+ }
}
- push_regs (live_regs_mask);
+
+ push_regs (live_regs_mask, live_regs_mask2);
+
output_stack_adjust (-get_frame_size (), stack_pointer_rtx);
if (frame_pointer_needed)
@@ -1951,7 +1988,8 @@ sh_expand_epilogue ()
int live_regs_mask;
int d, i;
- live_regs_mask = calc_live_regs (&d);
+ int live_regs_mask2;
+ live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
if (frame_pointer_needed)
{
@@ -1970,7 +2008,9 @@ sh_expand_epilogue ()
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int j = (FIRST_PSEUDO_REGISTER - 1) - i;
- if (live_regs_mask & (1 << j))
+ if (j < 32 && (live_regs_mask & (1 << j)))
+ pop (j);
+ else if (j >= 32 && (live_regs_mask2 & (1 << (j - 32))))
pop (j);
}
@@ -1988,6 +2028,62 @@ function_epilogue (stream, size)
pragma_interrupt = pragma_trapa = pragma_nosave_low_regs = 0;
}
+rtx
+sh_builtin_saveregs (arglist)
+ tree arglist;
+{
+ tree fntype = TREE_TYPE (current_function_decl);
+ /* First unnamed integer register. */
+ int first_intreg = current_function_args_info.arg_count[(int) SH_ARG_INT];
+ /* Number of integer registers we need to save. */
+ int n_intregs = MAX (0, NPARM_REGS (SImode) - first_intreg);
+ /* First unnamed SFmode float reg */
+ int first_floatreg = current_function_args_info.arg_count[(int) SH_ARG_FLOAT];
+ /* Number of SFmode float regs to save. */
+ int n_floatregs = MAX (0, NPARM_REGS (SFmode) - first_floatreg);
+ int ptrsize = GET_MODE_SIZE (Pmode);
+ rtx valist, regbuf, fpregs;
+ int bufsize, regno;
+
+ /* Allocate block of memory for the regs. */
+ /* ??? If n_intregs + n_floatregs == 0, should we allocate at least 1 byte?
+ Or can assign_stack_local accept a 0 SIZE argument? */
+ bufsize = (n_intregs * UNITS_PER_WORD) + (n_floatregs * UNITS_PER_WORD);
+
+ regbuf = assign_stack_local (BLKmode, bufsize, 0);
+ MEM_IN_STRUCT_P (regbuf) = 1;
+
+ /* Save int args.
+ This is optimized to only save the regs that are necessary. Explicitly
+ named args need not be saved. */
+ if (n_intregs > 0)
+ move_block_from_reg (BASE_ARG_REG (SImode) + first_intreg,
+ gen_rtx (MEM, BLKmode,
+ plus_constant (XEXP (regbuf, 0),
+ n_floatregs * UNITS_PER_WORD)),
+ n_intregs, n_intregs * UNITS_PER_WORD);
+
+ /* Save float args.
+ This is optimized to only save the regs that are necessary. Explicitly
+ named args need not be saved.
+ We explicitly build a pointer to the buffer because it halves the insn
+ count when not optimizing (otherwise the pointer is built for each reg
+ saved). */
+
+ fpregs = gen_reg_rtx (Pmode);
+ emit_move_insn (fpregs, XEXP (regbuf, 0));
+ for (regno = first_floatreg; regno < NPARM_REGS (SFmode); regno ++)
+ emit_move_insn (gen_rtx (MEM, SFmode,
+ plus_constant (fpregs,
+ GET_MODE_SIZE (SFmode)
+ * (regno - first_floatreg))),
+ gen_rtx (REG, SFmode,
+ BASE_ARG_REG (SFmode) + regno));
+
+ /* Return the address of the regbuf. */
+ return XEXP (regbuf, 0);
+}
+
/* Define the offset between two registers, one to be eliminated, and
the other its replacement, at the start of a routine. */
@@ -2000,7 +2096,9 @@ initial_elimination_offset (from, to)
int total_saved_regs_space;
int total_auto_space = get_frame_size ();
- calc_live_regs (&regs_saved);
+ int live_regs_mask2;
+ calc_live_regs (&regs_saved, &live_regs_mask2);
+
total_saved_regs_space = (regs_saved) * 4;
if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
@@ -2138,6 +2236,7 @@ arith_reg_operand (op, mode)
if (GET_CODE (op) == REG)
return (REGNO (op) != T_REG
&& REGNO (op) != PR_REG
+ && REGNO (op) != FPUL_REG
&& REGNO (op) != MACH_REG
&& REGNO (op) != MACL_REG);
return 1;
@@ -2192,60 +2291,35 @@ logical_operand (op, mode)
return 0;
}
-
-/* Determine where to put an argument to a function.
- Value is zero to push the argument on the stack,
- or a hard register in which to store the argument.
-
- MODE is the argument's machine mode.
- TYPE is the data type of the argument (as a tree).
- This is null for libcalls where that information may
- not be available.
- CUM is a variable of type CUMULATIVE_ARGS which gives info about
- the preceding args and about the function being called.
- NAMED is nonzero if this argument is a named parameter
- (otherwise it is an extra parameter matching an ellipsis). */
-rtx
-sh_function_arg (cum, mode, type, named)
- CUMULATIVE_ARGS cum;
- enum machine_mode mode;
- tree type;
- int named;
+/* Nonzero if OP is a floating point value with value 0.0. */
+
+int
+fp_zero_operand (op)
+ rtx op;
{
- if (named)
- {
- int rr = (ROUND_REG (cum, mode));
+ REAL_VALUE_TYPE r;
- if (rr < NPARM_REGS)
- return ((type == 0 || ! TREE_ADDRESSABLE (type))
- ? gen_rtx (REG, mode, FIRST_PARM_REG + rr) : 0);
- }
- return 0;
+ if (GET_MODE (op) != SFmode)
+ return 0;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+ return REAL_VALUES_EQUAL (r, dconst0);
}
-/* For an arg passed partly in registers and partly in memory,
- this is the number of registers used.
- For args passed entirely in registers or entirely in memory, zero.
- Any arg that starts in the first 4 regs but won't entirely fit in them
- needs partial registers on the SH. */
+/* Nonzero if OP is a floating point value with value 1.0. */
int
-sh_function_arg_partial_nregs (cum, mode, type, named)
- CUMULATIVE_ARGS cum;
- enum machine_mode mode;
- tree type;
- int named;
+fp_one_operand (op)
+ rtx op;
{
- if (cum < NPARM_REGS)
- {
- if ((type == 0 || ! TREE_ADDRESSABLE (type))
- && (cum + (mode == BLKmode
- ? ROUND_ADVANCE (int_size_in_bytes (type))
- : ROUND_ADVANCE (GET_MODE_SIZE (mode))) - NPARM_REGS > 0))
- return NPARM_REGS - cum;
- }
- return 0;
+ REAL_VALUE_TYPE r;
+
+ if (GET_MODE (op) != SFmode)
+ return 0;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+ return REAL_VALUES_EQUAL (r, dconst1);
}
/* Return non-zero if REG is not used after INSN.