OSDN Git Service

2010-04-13 Steve Ellcey <sje@cup.hp.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-tailcall.c
index d651c3b..969e07d 100644 (file)
@@ -23,7 +23,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "rtl.h"
 #include "tm_p.h"
+#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "function.h"
 #include "tree-flow.h"
@@ -131,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
@@ -419,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);
@@ -450,6 +473,15 @@ 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