diff options
author | kkojima <kkojima@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 14:28:34 +0000 |
---|---|---|
committer | kkojima <kkojima@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 14:28:34 +0000 |
commit | be0c0b379fa2aaded38558440f421c66224fb24e (patch) | |
tree | f66527dccc56b711aaa73b6d6d045c133c0203ab | |
parent | 9f38cf7c5e919acaa7a7c69f4d4b1364780b3835 (diff) | |
download | gcc-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/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/config/sh/sh-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 73 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 4 |
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; }") |