aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2009-11-26 10:44:28 +0000
committerNick Clifton <nickc@gcc.gnu.org>2009-11-26 10:44:28 +0000
commit0d8f38d33736f6cc7fbd8322e1ec8b67184ce454 (patch)
tree5e7ee5d5da5e4e095ba98a11720f3e4caa104352 /gcc
parent5d6b1baca04732559753fbd217aaf40b0463c4a0 (diff)
downloadgcc-0d8f38d33736f6cc7fbd8322e1ec8b67184ce454.zip
gcc-0d8f38d33736f6cc7fbd8322e1ec8b67184ce454.tar.gz
gcc-0d8f38d33736f6cc7fbd8322e1ec8b67184ce454.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/rx/rx.c53
-rw-r--r--gcc/config/rx/rx.md52
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 <nickc@redhat.com>
+
+ * 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 <rth@redhat.com>
* 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")]
)