From 1a95a9637341ec6541d8bb05508d8b35e0f16c03 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Thu, 18 Jan 1996 14:41:00 -0800 Subject: [PATCH] (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 --- gcc/config/sh/sh.c | 242 +++++++++++++++++++++++++++++---------------- 1 file changed, 158 insertions(+), 84 deletions(-) diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 81125b3e41c..1a9cda919c1 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 #include #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 (®s_saved); + int live_regs_mask2; + calc_live_regs (®s_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; -{ - if (named) - { - int rr = (ROUND_REG (cum, mode)); - - if (rr < NPARM_REGS) - return ((type == 0 || ! TREE_ADDRESSABLE (type)) - ? gen_rtx (REG, mode, FIRST_PARM_REG + rr) : 0); - } - return 0; -} - -/* 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 0.0. */ int -sh_function_arg_partial_nregs (cum, mode, type, named) - CUMULATIVE_ARGS cum; - enum machine_mode mode; - tree type; - int named; +fp_zero_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, dconst0); +} + +/* Nonzero if OP is a floating point value with value 1.0. */ + +int +fp_one_operand (op) + rtx op; +{ + 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.