OSDN Git Service

PR target/40603
[pf3gnuchains/gcc-fork.git] / gcc / tree-tailcall.c
index 4d2422a..969e07d 100644 (file)
@@ -133,6 +133,26 @@ suitable_for_tail_opt_p (void)
   if (cfun->stdarg)
     return false;
 
+  /* No local variable nor structure field should escape to callees.  */
+  FOR_EACH_REFERENCED_VAR (var, rvi)
+    {
+      if (!is_global_var (var)
+         /* ???  We do not have a suitable predicate for escaping to
+            callees.  With IPA-PTA the following might be incorrect.
+            We want to catch
+              foo {
+                int i;
+                bar (&i);
+                foo ();
+              }
+            where bar might store &i somewhere and in the next
+            recursion should not be able to tell if it got the
+            same (with tail-recursion applied) or a different
+            address.  */
+         && is_call_clobbered (var))
+       return false;
+    }
+
   return true;
 }
 /* Returns false when the function is not suitable for tail call optimization
@@ -421,7 +441,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
   func = gimple_call_fndecl (call);
   if (func == current_function_decl)
     {
-      tree arg;
+      tree arg, var;
+      referenced_var_iterator rvi;
 
       for (param = DECL_ARGUMENTS (func), idx = 0;
           param && idx < gimple_call_num_args (call);
@@ -452,14 +473,25 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
        }
       if (idx == gimple_call_num_args (call) && !param)
        tail_recursion = true;
+
+      /* Make sure the tail invocation of this function does not refer
+        to local variables.  */
+      FOR_EACH_REFERENCED_VAR (var, rvi)
+       {
+         if (!is_global_var (var)
+             && ref_maybe_used_by_stmt_p (call, var))
+           return;
+       }
     }
 
   /* Make sure the tail invocation of this function does not refer
      to local variables.  */
   FOR_EACH_REFERENCED_VAR (var, rvi)
     {
-      if (!is_global_var (var)
-         && ref_maybe_used_by_stmt_p (call, 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;
     }