Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / gcc / tree-tailcall.c
index 66fb892..c6581dc 100644 (file)
@@ -1,6 +1,5 @@
 /* Tail call optimization on trees.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2003-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -27,7 +26,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "basic-block.h"
 #include "function.h"
 #include "tree-flow.h"
-#include "tree-dump.h"
 #include "gimple-pretty-print.h"
 #include "except.h"
 #include "tree-pass.h"
@@ -35,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "dbgcnt.h"
 #include "target.h"
+#include "cfgloop.h"
 #include "common/common-target.h"
 
 /* The file implements the tail recursion elimination.  It is also used to
@@ -391,7 +390,6 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
   basic_block abb;
   size_t idx;
   tree var;
-  referenced_var_iterator rvi;
 
   if (!single_succ_p (bb))
     return;
@@ -485,7 +483,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
 
   /* Make sure the tail invocation of this function does not refer
      to local variables.  */
-  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
+  FOR_EACH_LOCAL_DECL (cfun, idx, var)
     {
       if (TREE_CODE (var) != PARM_DECL
          && auto_var_in_fn_p (var, cfun->decl)
@@ -611,14 +609,11 @@ 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_reg (ret_type, label);
+  tree result = make_temp_ssa_name (ret_type, NULL, label);
   gimple stmt;
-  tree result;
-
-  add_referenced_var (tmp);
 
   if (types_compatible_p (TREE_TYPE (acc), TREE_TYPE (op1)))
-    stmt = gimple_build_assign_with_ops (code, tmp, acc, op1);
+    stmt = gimple_build_assign_with_ops (code, result, acc, op1);
   else
     {
       tree rhs = fold_convert (TREE_TYPE (acc),
@@ -628,12 +623,9 @@ adjust_return_value_with_ops (enum tree_code code, const char *label,
                                            op1));
       rhs = force_gimple_operand_gsi (&gsi, rhs,
                                      false, NULL, true, GSI_SAME_STMT);
-      stmt = gimple_build_assign (NULL_TREE, rhs);
+      stmt = gimple_build_assign (result, rhs);
     }
 
-  result = make_ssa_name (tmp, stmt);
-  gimple_assign_set_lhs (stmt, result);
-  update_stmt (stmt);
   gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);
   return result;
 }
@@ -648,9 +640,9 @@ update_accumulator_with_ops (enum tree_code code, tree acc, tree op1,
                             gimple_stmt_iterator gsi)
 {
   gimple stmt;
-  tree var;
+  tree var = copy_ssa_name (acc, NULL);
   if (types_compatible_p (TREE_TYPE (acc), TREE_TYPE (op1)))
-    stmt = gimple_build_assign_with_ops (code, SSA_NAME_VAR (acc), acc, op1);
+    stmt = gimple_build_assign_with_ops (code, var, acc, op1);
   else
     {
       tree rhs = fold_convert (TREE_TYPE (acc),
@@ -660,11 +652,8 @@ update_accumulator_with_ops (enum tree_code code, tree acc, tree op1,
                                            op1));
       rhs = force_gimple_operand_gsi (&gsi, rhs,
                                      false, NULL, false, GSI_CONTINUE_LINKING);
-      stmt = gimple_build_assign (NULL_TREE, rhs);
+      stmt = gimple_build_assign (var, rhs);
     }
-  var = make_ssa_name (SSA_NAME_VAR (acc), stmt);
-  gimple_assign_set_lhs (stmt, var);
-  update_stmt (stmt);
   gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
   return var;
 }
@@ -767,11 +756,11 @@ arg_needs_copy_p (tree param)
 {
   tree def;
 
-  if (!is_gimple_reg (param) || !var_ann (param))
+  if (!is_gimple_reg (param))
     return false;
 
   /* Parameters that are only defined but never used need not be copied.  */
-  def = gimple_default_def (cfun, param);
+  def = ssa_default_def (cfun, param);
   if (!def)
     return false;
 
@@ -873,36 +862,6 @@ eliminate_tail_call (struct tailcall *t)
   release_defs (call);
 }
 
-/* Add phi nodes for the virtual operands defined in the function to the
-   header of the loop created by tail recursion elimination.
-
-   Originally, we used to add phi nodes only for call clobbered variables,
-   as the value of the non-call clobbered ones obviously cannot be used
-   or changed within the recursive call.  However, the local variables
-   from multiple calls now share the same location, so the virtual ssa form
-   requires us to say that the location dies on further iterations of the loop,
-   which requires adding phi nodes.
-*/
-static void
-add_virtual_phis (void)
-{
-  referenced_var_iterator rvi;
-  tree var;
-
-  /* The problematic part is that there is no way how to know what
-     to put into phi nodes (there in fact does not have to be such
-     ssa name available).  A solution would be to have an artificial
-     use/kill for all virtual operands in EXIT node.  Unless we have
-     this, we cannot do much better than to rebuild the ssa form for
-     possibly affected virtual ssa names from scratch.  */
-
-  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
-    {
-      if (!is_gimple_reg (var) && gimple_default_def (cfun, var) != NULL_TREE)
-       mark_sym_for_renaming (var);
-    }
-}
-
 /* Optimizes the tailcall described by T.  If OPT_TAILCALLS is true, also
    mark the tailcalls for the sibcall optimization.  */
 
@@ -941,10 +900,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_reg (ret_type, label);
+  tree tmp = make_temp_ssa_name (ret_type, NULL, label);
   gimple phi;
 
-  add_referenced_var (tmp);
   phi = create_phi_node (tmp, bb);
   /* RET_TYPE can be a float when -ffast-maths is enabled.  */
   add_phi_arg (phi, fold_convert (ret_type, init), single_pred_edge (bb),
@@ -1004,13 +962,12 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
               param = DECL_CHAIN (param))
            if (arg_needs_copy_p (param))
              {
-               tree name = gimple_default_def (cfun, param);
+               tree name = ssa_default_def (cfun, param);
                tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
                gimple phi;
 
-               set_default_def (param, new_name);
+               set_ssa_default_def (cfun, param, new_name);
                phi = create_phi_node (name, first);
-               SSA_NAME_DEF_STMT (name) = phi;
                add_phi_arg (phi, new_name, single_pred_edge (first),
                             EXPR_LOCATION (param));
              }
@@ -1055,10 +1012,19 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
     }
 
   if (changed)
-    free_dominance_info (CDI_DOMINATORS);
+    {
+      /* We may have created new loops.  Make them magically appear.  */
+      if (current_loops)
+       loops_state_set (LOOPS_NEED_FIXUP);
+      free_dominance_info (CDI_DOMINATORS);
+    }
 
+  /* Add phi nodes for the virtual operands defined in the function to the
+     header of the loop created by tail recursion elimination.  Do so
+     by triggering the SSA renamer.  */
   if (phis_constructed)
-    add_virtual_phis ();
+    mark_virtual_operands_for_renaming (cfun);
+
   if (changed)
     return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
   return 0;
@@ -1087,6 +1053,7 @@ struct gimple_opt_pass pass_tail_recursion =
  {
   GIMPLE_PASS,
   "tailr",                             /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   gate_tail_calls,                     /* gate */
   execute_tail_recursion,              /* execute */
   NULL,                                        /* sub */
@@ -1106,6 +1073,7 @@ struct gimple_opt_pass pass_tail_calls =
  {
   GIMPLE_PASS,
   "tailc",                             /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   gate_tail_calls,                     /* gate */
   execute_tail_calls,                  /* execute */
   NULL,                                        /* sub */