summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkkojima <kkojima@138bc75d-0d04-0410-961f-82ee72b054a4>2004-05-13 14:28:34 +0000
committerkkojima <kkojima@138bc75d-0d04-0410-961f-82ee72b054a4>2004-05-13 14:28:34 +0000
commitbe0c0b379fa2aaded38558440f421c66224fb24e (patch)
treef66527dccc56b711aaa73b6d6d045c133c0203ab
parent9f38cf7c5e919acaa7a7c69f4d4b1364780b3835 (diff)
downloadgcc-be0c0b379fa2aaded38558440f421c66224fb24e.tar.gz
PR target/15130
* config/sh/sh-protos.h (sh_expand_epilogue): Change prototype. * config/sh/sh.c (output_stack_adjust): Generate a special push/pop sequence when failing to get a temporary register for non SHmedia epilogue. (sh_expand_epilogue): Add an argument to show whether it's for sibcall or not. Take the sibcall epilogue into account. (sh_need_epilogue): Call sh_expand_epilogue with 0. * config/sh/sh.md (sibcall_epilogue): Call sh_expand_epilogue with 1. (epilogue): Call sh_expand_epilogue with 0. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-3_3-branch@81783 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/config/sh/sh-protos.h2
-rw-r--r--gcc/config/sh/sh.c73
-rw-r--r--gcc/config/sh/sh.md4
4 files changed, 84 insertions, 9 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index efef8d2c6fe..4575407b114 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2004-05-13 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ PR target/15130
+ * config/sh/sh-protos.h (sh_expand_epilogue): Change prototype.
+ * config/sh/sh.c (output_stack_adjust): Generate a special
+ push/pop sequence when failing to get a temporary register for
+ non SHmedia epilogue.
+ (sh_expand_epilogue): Add an argument to show whether it's for
+ sibcall or not. Take the sibcall epilogue into account.
+ (sh_need_epilogue): Call sh_expand_epilogue with 0.
+ * config/sh/sh.md (sibcall_epilogue): Call sh_expand_epilogue
+ with 1.
+ (epilogue): Call sh_expand_epilogue with 0.
+
2004-05-08 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* alias.c (set_reg_known_value, set_reg_known_equiv_p):
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index 7c294625330..197b97d9243 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -118,7 +118,7 @@ extern struct rtx_def *get_fpscr_rtx PARAMS ((void));
extern void output_file_start PARAMS ((FILE *));
extern int sh_media_register_for_return PARAMS ((void));
extern void sh_expand_prologue PARAMS ((void));
-extern void sh_expand_epilogue PARAMS ((void));
+extern void sh_expand_epilogue PARAMS ((bool));
extern int sh_need_epilogue PARAMS ((void));
extern int initial_elimination_offset PARAMS ((int, int));
extern int fldi_ok PARAMS ((void));
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 7ac5204fd82..e0cbbca88d5 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -4277,7 +4277,55 @@ output_stack_adjust (size, reg, temp, emit_fn)
register to MACL. However, there is currently no need
to handle this case, so just abort when we see it. */
if (temp < 0)
- abort ();
+ {
+ /* If we reached here, the most likely case is the (sibcall)
+ epilogue for non SHmedia. Put a special push/pop sequence
+ for such case as the last resort. This looks lengthy but
+ would not be problem because it seems to be very rare. */
+ if (! TARGET_SHMEDIA && (emit_fn != frame_insn))
+ {
+ rtx adj_reg, tmp_reg, mem;
+
+ /* ??? There is still the slight possibility that r4 or r5
+ have been reserved as fixed registers or assigned as
+ global registers, and they change during an interrupt.
+ There are possible ways to handle this:
+ - If we are adjusting the frame pointer (r14), we can do
+ with a single temp register and an ordinary push / pop
+ on the stack.
+ - Grab any call-used or call-saved registers (i.e. not
+ fixed or globals) for the temps we need. We might
+ also grab r14 if we are adjusting the stack pointer.
+ If we can't find enough available registers, issue
+ a diagnostic and abort - the user must have reserved
+ way too many registers.
+ But since all this is rather unlikely to happen and
+ would require extra testing, we just abort if r4 / r5
+ are not available. */
+ if (fixed_regs[4] || fixed_regs[5]
+ || global_regs[4] || global_regs[5])
+ abort ();
+
+ adj_reg = gen_rtx_REG (GET_MODE (reg), 4);
+ tmp_reg = gen_rtx_REG (GET_MODE (reg), 5);
+ emit_move_insn (gen_rtx_MEM (Pmode, reg), adj_reg);
+ emit_insn (GEN_MOV (adj_reg, GEN_INT (size)));
+ emit_insn (GEN_ADD3 (adj_reg, adj_reg, reg));
+ mem = gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
+ emit_move_insn (mem, tmp_reg);
+ emit_move_insn (tmp_reg, gen_rtx_MEM (Pmode, reg));
+ mem = gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
+ emit_move_insn (mem, tmp_reg);
+ emit_move_insn (reg, adj_reg);
+ mem = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, reg));
+ emit_move_insn (adj_reg, mem);
+ mem = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, reg));
+ emit_move_insn (tmp_reg, mem);
+ return;
+ }
+ else
+ abort ();
+ }
const_reg = gen_rtx_REG (GET_MODE (reg), temp);
/* If SIZE is negative, subtract the positive value.
@@ -4843,7 +4891,7 @@ sh_expand_prologue ()
}
void
-sh_expand_epilogue ()
+sh_expand_epilogue (bool sibcall_p)
{
HOST_WIDE_INT live_regs_mask[(FIRST_PSEUDO_REGISTER + 31) / 32];
int d, i;
@@ -4851,9 +4899,22 @@ sh_expand_epilogue ()
int save_flags = target_flags;
int frame_size;
+ int temp;
calc_live_regs (&d, live_regs_mask);
+ if (! sibcall_p)
+ temp = 7;
+ else if (TARGET_SHMEDIA)
+ temp = 1;
+ else
+ {
+ for (i = FIRST_GENERAL_REG; i <= LAST_GENERAL_REG; i++)
+ if (TEST_HARD_REG_BIT (live_regs_mask, i))
+ break;
+ temp = (i <= LAST_GENERAL_REG) ? i : -1;
+ }
+
if (TARGET_SH5 && d % (STACK_BOUNDARY / BITS_PER_UNIT))
d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT)
- d % (STACK_BOUNDARY / BITS_PER_UNIT));
@@ -4862,7 +4923,7 @@ sh_expand_epilogue ()
if (frame_pointer_needed)
{
- output_stack_adjust (frame_size, frame_pointer_rtx, 7, emit_insn);
+ output_stack_adjust (frame_size, frame_pointer_rtx, temp, emit_insn);
/* We must avoid moving the stack pointer adjustment past code
which reads from the local frame, else an interrupt could
@@ -4878,7 +4939,7 @@ sh_expand_epilogue ()
occur after the SP adjustment and clobber data in the local
frame. */
emit_insn (gen_blockage ());
- output_stack_adjust (frame_size, stack_pointer_rtx, 7, emit_insn);
+ output_stack_adjust (frame_size, stack_pointer_rtx, temp, emit_insn);
}
if (SHMEDIA_REGS_STACK_ADJUST ())
@@ -5054,7 +5115,7 @@ sh_expand_epilogue ()
output_stack_adjust (extra_push + current_function_pretend_args_size
+ d + d_rounding
+ current_function_args_info.stack_regs * 8,
- stack_pointer_rtx, 7, emit_insn);
+ stack_pointer_rtx, (sibcall_p ? -1 : temp), emit_insn);
/* Switch back to the normal stack if necessary. */
if (sp_switch)
@@ -5078,7 +5139,7 @@ sh_need_epilogue ()
rtx epilogue;
start_sequence ();
- sh_expand_epilogue ();
+ sh_expand_epilogue (0);
epilogue = get_insns ();
end_sequence ();
sh_need_epilogue_known = (epilogue == NULL ? -1 : 1);
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 21dca6e7ecf..41106d502df 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -6414,7 +6414,7 @@
""
"
{
- sh_expand_epilogue ();
+ sh_expand_epilogue (1);
if (TARGET_SHCOMPACT)
{
rtx insn, set;
@@ -7158,7 +7158,7 @@
""
"
{
- sh_expand_epilogue ();
+ sh_expand_epilogue (0);
emit_jump_insn (gen_return ());
DONE;
}")