OSDN Git Service

* config/m32c/m32c-protos.h (m32c_function_arg): Delete.
[pf3gnuchains/gcc-fork.git] / gcc / tree-tailcall.c
index bf8ebb8..65eaa40 100644 (file)
@@ -1,5 +1,5 @@
 /* Tail call optimization on trees.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,14 +23,12 @@ 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"
 #include "tree-dump.h"
-#include "diagnostic.h"
+#include "gimple-pretty-print.h"
 #include "except.h"
 #include "tree-pass.h"
 #include "flags.h"
@@ -130,20 +128,9 @@ static void find_tail_calls (basic_block, struct tailcall **);
 static bool
 suitable_for_tail_opt_p (void)
 {
-  referenced_var_iterator rvi;
-  tree var;
-
   if (cfun->stdarg)
     return false;
 
-  /* No local variable nor structure field should be call-used.  */
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    {
-      if (!is_global_var (var)
-         && is_call_used (var))
-       return false;
-    }
-
   return true;
 }
 /* Returns false when the function is not suitable for tail call optimization
@@ -177,7 +164,7 @@ suitable_for_tail_call_opt_p (void)
      but not in all cases.  See PR15387 and PR19616.  Revisit for 4.1.  */
   for (param = DECL_ARGUMENTS (current_function_decl);
        param;
-       param = TREE_CHAIN (param))
+       param = DECL_CHAIN (param))
     if (TREE_ADDRESSABLE (param))
       return false;
 
@@ -375,6 +362,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
   tree m, a;
   basic_block abb;
   size_t idx;
+  tree var;
+  referenced_var_iterator rvi;
 
   if (!single_succ_p (bb))
     return;
@@ -431,9 +420,10 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
   if (func == current_function_decl)
     {
       tree arg;
+
       for (param = DECL_ARGUMENTS (func), idx = 0;
           param && idx < gimple_call_num_args (call);
-          param = TREE_CHAIN (param), idx ++)
+          param = DECL_CHAIN (param), idx ++)
        {
          arg = gimple_call_arg (call, idx);
          if (param != arg)
@@ -462,6 +452,17 @@ 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.  */
+  FOR_EACH_REFERENCED_VAR (var, rvi)
+    {
+      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;
+    }
+
   /* Now check the statements after the call.  None of them has virtual
      operands, so they may only depend on the call through its return
      value.  The return value should also be dependent on each of them,
@@ -574,13 +575,10 @@ adjust_return_value_with_ops (enum tree_code code, const char *label,
 {
 
   tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
-  tree tmp = create_tmp_var (ret_type, label);
+  tree tmp = create_tmp_reg (ret_type, label);
   gimple stmt;
   tree result;
 
-  if (TREE_CODE (ret_type) == COMPLEX_TYPE
-      || TREE_CODE (ret_type) == VECTOR_TYPE)
-    DECL_GIMPLE_REG_P (tmp) = 1;
   add_referenced_var (tmp);
 
   if (types_compatible_p (TREE_TYPE (acc), TREE_TYPE (op1)))
@@ -810,7 +808,7 @@ eliminate_tail_call (struct tailcall *t)
   for (param = DECL_ARGUMENTS (current_function_decl),
         idx = 0, gsi = gsi_start_phis (first);
        param;
-       param = TREE_CHAIN (param), idx++)
+       param = DECL_CHAIN (param), idx++)
     {
       if (!arg_needs_copy_p (param))
        continue;
@@ -907,12 +905,9 @@ static tree
 create_tailcall_accumulator (const char *label, basic_block bb, tree init)
 {
   tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
-  tree tmp = create_tmp_var (ret_type, label);
+  tree tmp = create_tmp_reg (ret_type, label);
   gimple phi;
 
-  if (TREE_CODE (ret_type) == COMPLEX_TYPE
-      || TREE_CODE (ret_type) == VECTOR_TYPE)
-    DECL_GIMPLE_REG_P (tmp) = 1;
   add_referenced_var (tmp);
   phi = create_phi_node (tmp, bb);
   /* RET_TYPE can be a float when -ffast-maths is enabled.  */
@@ -970,7 +965,7 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
          /* Copy the args if needed.  */
          for (param = DECL_ARGUMENTS (current_function_decl);
               param;
-              param = TREE_CHAIN (param))
+              param = DECL_CHAIN (param))
            if (arg_needs_copy_p (param))
              {
                tree name = gimple_default_def (cfun, param);