Commit 2c28c3e4 by Richard Sandiford Committed by Richard Sandiford

Tighten check for whether sibcall references local variables

This loop:

      /* Make sure the tail invocation of this function does not refer
         to local variables.  */
      FOR_EACH_LOCAL_DECL (cfun, idx, var)
        {
          if (TREE_CODE (var) != PARM_DECL
              && auto_var_in_fn_p (var, cfun->decl)
              && (ref_maybe_used_by_stmt_p (call, var)
                  || call_may_clobber_ref_p (call, var)))
            return;
        }

triggered even for local variables that are passed by value.
This meant that we didn't allow local aggregates to be passed
to a sibling call but did (for example) allow global aggregates
to be passed.

I think the loop is really checking for indirect references,
so should be able to skip any variables that never have their
address taken.

gcc/
	* tree-tailcall.c (find_tail_calls): Allow calls to reference
	local variables if all references are known to be direct.

gcc/testsuite/
	* gcc.dg/tree-ssa/tailcall-8.c: New test.

From-SVN: r242860
parent 4ae35e69
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> 2016-11-25 Jakub Jelinek <jakub@redhat.com>
Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
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> 2016-11-25 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
* gcc.dg/pr64277.c: Use __INT32_TYPE__ for targets * gcc.dg/pr64277.c: Use __INT32_TYPE__ for targets
......
/* { 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" } } */
...@@ -504,12 +504,14 @@ find_tail_calls (basic_block bb, struct tailcall **ret) ...@@ -504,12 +504,14 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
tail_recursion = true; tail_recursion = true;
} }
/* Make sure the tail invocation of this function does not refer /* Make sure the tail invocation of this function does not indirectly
to local variables. */ refer to local variables. (Passing variables directly by value
is OK.) */
FOR_EACH_LOCAL_DECL (cfun, idx, var) FOR_EACH_LOCAL_DECL (cfun, idx, var)
{ {
if (TREE_CODE (var) != PARM_DECL if (TREE_CODE (var) != PARM_DECL
&& auto_var_in_fn_p (var, cfun->decl) && auto_var_in_fn_p (var, cfun->decl)
&& may_be_aliased (var)
&& (ref_maybe_used_by_stmt_p (call, var) && (ref_maybe_used_by_stmt_p (call, var)
|| call_may_clobber_ref_p (call, var))) || call_may_clobber_ref_p (call, var)))
return; return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment