aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/sparc/sparc.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>1999-11-30 23:18:21 +0100
committerRichard Henderson <rth@gcc.gnu.org>1999-11-30 14:18:21 -0800
commite48addeebcc08efa9cd2a13fd2e70e2c92db26d8 (patch)
treea0aa3f53fbb63793261d833b1f8613a481049e03 /gcc/config/sparc/sparc.c
parentf34e52f774c16f4042cc44ddb471dd141a5dc583 (diff)
downloadgcc-e48addeebcc08efa9cd2a13fd2e70e2c92db26d8.zip
gcc-e48addeebcc08efa9cd2a13fd2e70e2c92db26d8.tar.gz
gcc-e48addeebcc08efa9cd2a13fd2e70e2c92db26d8.tar.bz2
Jakub Jelinek <jakub@redhat.com>
* config/sparc/sparc.h (FIXED_REGISTERS, CONDITIONAL_REGISTER_USAGE): Allow the user to override call-used/fixed state of %g2-5 registers from the command line (with the exception of %g4 for embedded model). (REG_LEAF_ALLOC_ORDER): Move %g1 and %g4-7 registers to front, so that there is a higher chance of having a leaf function. (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Provide separate macros for ARCH64 which has %ccr register. * config/sparc/sparc.md (return_losum_si, return_losum_di): New patterns. * config/sparc/sparc.c (eligible_for_epilogue_delay): For the return insn accept into delay slot any insn which does not use %[ol] registers. Accept some LO_SUM and shift left by 1 for the normal restore case. (output_function_epilogue): Likewise. (epilogue_renumber): Added argument which inhibits any renumbering and just tests if the rtx does not use any %[ol] registers. (output_return): Reflect above change. From-SVN: r30727
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r--gcc/config/sparc/sparc.c169
1 files changed, 111 insertions, 58 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 54c0230..22c0fbf 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -63,6 +63,10 @@ Boston, MA 02111-1307, USA. */
static int apparent_fsize;
static int actual_fsize;
+/* Number of live general or floating point registers needed to be saved
+ (as 4-byte quantities). This is only done if TARGET_EPILOGUE. */
+static int num_gfregs;
+
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
@@ -124,7 +128,7 @@ static void sparc_output_deferred_case_vectors PROTO((void));
static void sparc_add_gc_roots PROTO ((void));
static void mark_ultrasparc_pipeline_state PROTO ((void *));
static int check_return_regs PROTO ((rtx));
-static void epilogue_renumber PROTO ((rtx *));
+static int epilogue_renumber PROTO ((rtx *, int));
static int ultra_cmove_results_ready_p PROTO ((rtx));
static int ultra_fpmode_conflict_exists PROTO ((enum machine_mode));
static rtx *ultra_find_type PROTO ((int, rtx *, int));
@@ -2208,6 +2212,11 @@ eligible_for_epilogue_delay (trial, slot)
optimize things as necessary. */
if (TARGET_LIVE_G0)
return 0;
+
+ /* If there are any call-saved registers, we should scan TRIAL if it
+ does not reference them. For now just make it easy. */
+ if (num_gfregs)
+ return 0;
/* In the case of a true leaf function, anything can go into the delay slot.
A delay slot only exists however if the frame size is zero, otherwise
@@ -2228,7 +2237,7 @@ eligible_for_epilogue_delay (trial, slot)
pat = PATTERN (trial);
/* Otherwise, only operations which can be done in tandem with
- a `restore' insn can go into the delay slot. */
+ a `restore' or `return' insn can go into the delay slot. */
if (GET_CODE (SET_DEST (pat)) != REG
|| REGNO (SET_DEST (pat)) >= 32
|| REGNO (SET_DEST (pat)) < 24)
@@ -2247,7 +2256,7 @@ eligible_for_epilogue_delay (trial, slot)
else
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
}
-
+
/* This matches "*return_di". */
else if (arith_double_operand (src, GET_MODE (src)))
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
@@ -2257,6 +2266,12 @@ eligible_for_epilogue_delay (trial, slot)
&& register_operand (src, SFmode))
return 1;
+ /* If we have return instruction, anything that does not use
+ local or output registers and can go into a delay slot wins. */
+ else if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
+ && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
+ return 1;
+
/* This matches "*return_addsi". */
else if (GET_CODE (src) == PLUS
&& arith_operand (XEXP (src, 0), SImode)
@@ -2273,6 +2288,25 @@ eligible_for_epilogue_delay (trial, slot)
|| register_operand (XEXP (src, 1), DImode)))
return 1;
+ /* This can match "*return_losum_[sd]i".
+ Catch only some cases, so that return_losum* don't have
+ to be too big. */
+ else if (GET_CODE (src) == LO_SUM
+ && ! TARGET_CM_MEDMID
+ && ((register_operand (XEXP (src, 0), SImode)
+ && immediate_operand (XEXP (src, 1), SImode))
+ || (TARGET_ARCH64
+ && register_operand (XEXP (src, 0), DImode)
+ && immediate_operand (XEXP (src, 1), DImode))))
+ return 1;
+
+ /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well. */
+ else if (GET_CODE (src) == ASHIFT
+ && (register_operand (XEXP (src, 0), SImode)
+ || register_operand (XEXP (src, 0), DImode))
+ && XEXP (src, 1) == const1_rtx)
+ return 1;
+
return 0;
}
@@ -2979,12 +3013,6 @@ restore_regs (file, low, high, base, offset, n_regs)
return n_regs;
}
-/* Static variables we want to share between prologue and epilogue. */
-
-/* Number of live general or floating point registers needed to be saved
- (as 4-byte quantities). This is only done if TARGET_EPILOGUE. */
-static int num_gfregs;
-
/* Compute the frame size required by the function. This function is called
during the reload pass and also by output_function_prologue(). */
@@ -3283,7 +3311,7 @@ output_function_epilogue (file, size, leaf_function)
#endif
else if (current_function_epilogue_delay_list == 0)
- {
+ {
/* If code does not drop into the epilogue, we need
do nothing except output pending case vectors. */
rtx insn = get_last_insn ();
@@ -3339,13 +3367,38 @@ output_function_epilogue (file, size, leaf_function)
/* If we wound up with things in our delay slot, flush them here. */
if (current_function_epilogue_delay_list)
{
- rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
- get_last_insn ());
- PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
- gen_rtvec (2,
- PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
- PATTERN (insn)));
- final_scan_insn (insn, file, 1, 0, 1);
+ rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
+
+ if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
+ {
+ epilogue_renumber (&delay, 0);
+ fputs (SKIP_CALLERS_UNIMP_P
+ ? "\treturn\t%i7+12\n"
+ : "\treturn\t%i7+8\n", file);
+ final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), file, 1, 0, 0);
+ }
+ else
+ {
+ rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
+ get_last_insn ());
+ rtx src;
+
+ if (GET_CODE (delay) != SET)
+ abort();
+
+ src = SET_SRC (delay);
+ if (GET_CODE (src) == ASHIFT)
+ {
+ if (XEXP (src, 1) != const1_rtx)
+ abort();
+ SET_SRC (delay) = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0),
+ XEXP (src, 0));
+ }
+
+ PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, delay, PATTERN (insn)));
+ final_scan_insn (insn, file, 1, 0, 1);
+ }
}
else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
fputs ("\treturn\t%i7+8\n\tnop\n", file);
@@ -4726,56 +4779,56 @@ output_v9branch (op, reg, label, reversed, annul, noop, insn)
return string;
}
-/* Renumber registers in delay slot. Replace registers instead of
- renumbering because they may be shared.
-
- This does not handle instructions other than move. */
+/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7].
+ Such instructions cannot be used in the delay slot of return insn on v9.
+ If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts.
+ */
-static void
-epilogue_renumber (where)
- rtx *where;
+static int
+epilogue_renumber (where, test)
+ register rtx *where;
+ int test;
{
- rtx x = *where;
- enum rtx_code code = GET_CODE (x);
+ register const char *fmt;
+ register int i;
+ register enum rtx_code code;
+
+ if (*where == 0)
+ return 0;
+
+ code = GET_CODE (*where);
switch (code)
{
- case MEM:
- *where = x = copy_rtx (x);
- epilogue_renumber (&XEXP (x, 0));
- return;
-
case REG:
- {
- int regno = REGNO (x);
- if (regno > 8 && regno < 24)
- abort ();
- if (regno >= 24 && regno < 32)
- *where = gen_rtx_REG (GET_MODE (x), regno - 16);
- return;
- }
+ if (REGNO (*where) >= 8 && REGNO (*where) < 24) /* oX or lX */
+ return 1;
+ if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
+ *where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
+ case SCRATCH:
+ case CC0:
+ case PC:
case CONST_INT:
case CONST_DOUBLE:
- case CONST:
- case SYMBOL_REF:
- case LABEL_REF:
- return;
+ return 0;
+ }
- case IOR:
- case AND:
- case XOR:
- case PLUS:
- case MINUS:
- epilogue_renumber (&XEXP (x, 1));
- case NEG:
- case NOT:
- epilogue_renumber (&XEXP (x, 0));
- return;
+ fmt = GET_RTX_FORMAT (code);
- default:
- debug_rtx (*where);
- abort ();
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ register int j;
+ for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
+ if (epilogue_renumber (&(XVECEXP (*where, i, j)), test))
+ return 1;
+ }
+ else if (fmt[i] == 'e'
+ && epilogue_renumber (&(XEXP (*where, i)), test))
+ return 1;
}
+ return 0;
}
/* Output assembler code to return from a function. */
@@ -4840,8 +4893,8 @@ output_return (operands)
{
if (delay)
{
- epilogue_renumber (&SET_DEST (PATTERN (delay)));
- epilogue_renumber (&SET_SRC (PATTERN (delay)));
+ epilogue_renumber (&SET_DEST (PATTERN (delay)), 0);
+ epilogue_renumber (&SET_SRC (PATTERN (delay)), 0);
}
if (SKIP_CALLERS_UNIMP_P)
return "return\t%%i7+12%#";