aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/tailcall-8.c80
-rw-r--r--gcc/tree-tailcall.c6
4 files changed, 93 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f2b4828..efc2016 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2016-11-25 Richard Sandiford <richard.sandiford@arm.com>
+
+ * tree-tailcall.c (find_tail_calls): Allow calls to reference
+ local variables if all references are known to be direct.
+
2016-11-25 Jakub Jelinek <jakub@redhat.com>
Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1028191..e18397f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2016-11-25 Richard Sandiford <richard.sandiford@arm.com>
+
+ * gcc.dg/tree-ssa/tailcall-8.c: New test.
+
2016-11-25 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
* gcc.dg/pr64277.c: Use __INT32_TYPE__ for targets
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-8.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-8.c
new file mode 100644
index 0000000..ffeabe5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-8.c
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-tailc-details" } */
+
+struct s { int x; };
+void f_direct (struct s);
+void f_indirect (struct s *);
+void f_void (void);
+
+/* Tail call. */
+void
+g1 (struct s param)
+{
+ f_direct (param);
+}
+
+/* Tail call. */
+void
+g2 (struct s *param_ptr)
+{
+ f_direct (*param_ptr);
+}
+
+/* Tail call. */
+void
+g3 (struct s *param_ptr)
+{
+ f_indirect (param_ptr);
+}
+
+/* Tail call. */
+void
+g4 (struct s *param_ptr)
+{
+ f_indirect (param_ptr);
+ f_void ();
+}
+
+/* Tail call. */
+void
+g5 (struct s param)
+{
+ struct s local = param;
+ f_direct (local);
+}
+
+/* Tail call. */
+void
+g6 (struct s param)
+{
+ struct s local = param;
+ f_direct (local);
+ f_void ();
+}
+
+/* Not a tail call. */
+void
+g7 (struct s param)
+{
+ struct s local = param;
+ f_indirect (&local);
+}
+
+/* Not a tail call. */
+void
+g8 (struct s *param_ptr)
+{
+ struct s local = *param_ptr;
+ f_indirect (&local);
+}
+
+/* Not a tail call. */
+void
+g9 (struct s *param_ptr)
+{
+ struct s local = *param_ptr;
+ f_indirect (&local);
+ f_void ();
+}
+
+/* { dg-final { scan-tree-dump-times "Found tail call" 6 "tailc" } } */
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index f97541d..66a0a4c 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -504,12 +504,14 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
tail_recursion = true;
}
- /* Make sure the tail invocation of this function does not refer
- to local variables. */
+ /* Make sure the tail invocation of this function does not indirectly
+ refer to local variables. (Passing variables directly by value
+ is OK.) */
FOR_EACH_LOCAL_DECL (cfun, idx, var)
{
if (TREE_CODE (var) != PARM_DECL
&& auto_var_in_fn_p (var, cfun->decl)
+ && may_be_aliased (var)
&& (ref_maybe_used_by_stmt_p (call, var)
|| call_may_clobber_ref_p (call, var)))
return;