From 0d8f38d33736f6cc7fbd8322e1ec8b67184ce454 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 26 Nov 2009 10:44:28 +0000 Subject: [PATCH] rx.c (rx_expand_epilogue): Add checks for sibcalls being used incorrectly. * config/rx/rx.c (rx_expand_epilogue): Add checks for sibcalls being used incorrectly. (rx_function_ok_for_sibcall): New function. Do not allow indirect sibcalls, or sibcalls from interrupt functions. (TARGET_FUNCTION_OK_FOR_SIBCALL): Define. * config/rx/rx.md (sibcall): Convert to a define_expand. Check for a MEM inside a MEM. (sibcall_value): Likewise. (sibcall_internal): New pattern containing old sibcall pattern. (sibcall_value_internal): Likewise. From-SVN: r154671 --- gcc/ChangeLog | 13 +++++++++++++ gcc/config/rx/rx.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- gcc/config/rx/rx.md | 52 ++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 103 insertions(+), 15 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e57f787..f493283 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2009-11-26 Nick Clifton + + * config/rx/rx.c (rx_expand_epilogue): Add checks for sibcalls + being used incorrectly. + (rx_function_ok_for_sibcall): New function. Do not allow indirect + sibcalls, or sibcalls from interrupt functions. + (TARGET_FUNCTION_OK_FOR_SIBCALL): Define. + * config/rx/rx.md (sibcall): Convert to a define_expand. Check + for a MEM inside a MEM. + (sibcall_value): Likewise. + (sibcall_internal): New pattern containing old sibcall pattern. + (sibcall_value_internal): Likewise. + 2009-11-25 Richard Henderson * config/i386/i386-builtin-types.awk (DEF_VECTOR_TYPE): Allow an diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c index 885f525..14cf09b 100644 --- a/gcc/config/rx/rx.c +++ b/gcc/config/rx/rx.c @@ -1190,7 +1190,7 @@ mark_frame_related (rtx insn) { unsigned int i; - for (i = 0; i < XVECLEN (insn, 0); i++) + for (i = 0; i < (unsigned) XVECLEN (insn, 0); i++) RTX_FRAME_RELATED_P (XVECEXP (insn, 0, i)) = 1; } } @@ -1454,8 +1454,26 @@ rx_expand_epilogue (bool is_sibcall) unsigned int reg; unsigned HOST_WIDE_INT total_size; + /* FIXME: We do not support indirect sibcalls at the moment becaause we + cannot guarantee that the register holding the function address is a + call-used register. If it is a call-saved register then the stack + pop instructions generated in the epilogue will corrupt the address + before it is used. + + Creating a new call-used-only register class works but then the + reload pass gets stuck because it cannot always find a call-used + register for spilling sibcalls. + + The other possible solution is for this pass to scan forward for the + sibcall instruction (if it has been generated) and work out if it + is an indirect sibcall using a call-saved register. If it is then + the address can copied into a call-used register in this epilogue + code and the sibcall instruction modified to use that register. */ + if (is_naked_func (NULL_TREE)) { + gcc_assert (! is_sibcall); + /* Naked functions use their own, programmer provided epilogues. But, in order to keep gcc happy we have to generate some kind of epilogue RTL. */ @@ -1547,9 +1565,15 @@ rx_expand_epilogue (bool is_sibcall) } if (is_fast_interrupt_func (NULL_TREE)) - emit_jump_insn (gen_fast_interrupt_return ()); + { + gcc_assert (! is_sibcall); + emit_jump_insn (gen_fast_interrupt_return ()); + } else if (is_interrupt_func (NULL_TREE)) - emit_jump_insn (gen_exception_return ()); + { + gcc_assert (! is_sibcall); + emit_jump_insn (gen_exception_return ()); + } else if (! is_sibcall) emit_jump_insn (gen_simple_return ()); @@ -2107,6 +2131,26 @@ rx_func_attr_inlinable (const_tree decl) && ! is_naked_func (decl); } +/* Return nonzero if it is ok to make a tail-call to DECL, + a function_decl or NULL if this is an indirect call, using EXP */ + +static bool +rx_function_ok_for_sibcall (tree decl, tree exp) +{ + /* Do not allow indirect tailcalls. The + sibcall patterns do not support them. */ + if (decl == NULL) + return false; + + /* Never tailcall from inside interrupt handlers or naked functions. */ + if (is_fast_interrupt_func (NULL_TREE) + || is_interrupt_func (NULL_TREE) + || is_naked_func (NULL_TREE)) + return false; + + return true; +} + static void rx_file_start (void) { @@ -2485,6 +2529,9 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain) #undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P #define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P rx_func_attr_inlinable +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL rx_function_ok_for_sibcall + #undef TARGET_SET_CURRENT_FUNCTION #define TARGET_SET_CURRENT_FUNCTION rx_set_current_function diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 360f623..a2c1c7c 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -388,7 +388,7 @@ (match_operand:SI 1 "general_operand" "g,g"))] "" "@ - jsr\t%A0 + jsr\t%0 bsr\t%A0" [(set_attr "length" "2,4") (set_attr "timings" "33")] @@ -415,32 +415,60 @@ (match_operand:SI 2 "general_operand" "g,g")))] "" "@ - jsr\t%A1 + jsr\t%1 bsr\t%A1" [(set_attr "length" "2,4") (set_attr "timings" "33")] ) -(define_insn "sibcall" - [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol")) - (match_operand:SI 1 "general_operand" "g")) - (return) - (use (match_operand 2 "" ""))] +;; Note - we do not allow indirect sibcalls (with the address +;; held in a register) because we cannot guarantee that the register +;; chosen will be a call-used one. If it is a call-saved register, +;; then the epilogue code will corrupt it by popping the saved value +;; off of the stack. +(define_expand "sibcall" + [(parallel + [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand")) + (match_operand:SI 1 "general_operand")) + (return)])] + "" + { + if (MEM_P (operands[0])) + operands[0] = XEXP (operands[0], 0); + } +) + +(define_insn "sibcall_internal" + [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol")) + (match_operand:SI 1 "general_operand" "g")) + (return)] "" "bra\t%A0" - [(set_attr "length" "4") + [(set_attr "length" "4") (set_attr "timings" "33")] ) -(define_insn "sibcall_value" +(define_expand "sibcall_value" + [(parallel + [(set (match_operand 0 "register_operand") + (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand")) + (match_operand:SI 2 "general_operand"))) + (return)])] + "" + { + if (MEM_P (operands[1])) + operands[1] = XEXP (operands[1], 0); + } +) + +(define_insn "sibcall_value_internal" [(set (match_operand 0 "register_operand" "=r") (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol")) (match_operand:SI 2 "general_operand" "g"))) - (return) - (use (match_operand 3 "" ""))] + (return)] "" "bra\t%A1" - [(set_attr "length" "4") + [(set_attr "length" "4") (set_attr "timings" "33")] ) -- 2.7.4