OSDN Git Service

* tree-inline.c (remap_decls): Enable nonlocalized variables
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 37d9098..f79424d 100644 (file)
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "input.h"
 #include "insn-config.h"
-#include "varray.h"
 #include "hashtab.h"
 #include "langhooks.h"
 #include "basic-block.h"
@@ -133,6 +132,7 @@ static tree copy_decl_to_var (tree, copy_body_data *);
 static tree copy_result_decl_to_var (tree, copy_body_data *);
 static tree copy_decl_maybe_to_var (tree, copy_body_data *);
 static gimple remap_gimple_stmt (gimple, copy_body_data *);
+static bool delete_unreachable_blocks_update_callgraph (copy_body_data *id);
 
 /* Insert a tree->tree mapping for ID.  Despite the name suggests
    that the trees should be variables, it is used for more than that.  */
@@ -501,7 +501,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
              && (var_ann (old_var) || !gimple_in_ssa_p (cfun)))
            cfun->local_decls = tree_cons (NULL_TREE, old_var,
                                                   cfun->local_decls);
-         if (debug_info_level > DINFO_LEVEL_TERSE
+         if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
              && !DECL_IGNORED_P (old_var)
              && nonlocalized_list)
            VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
@@ -519,7 +519,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
        ;
       else if (!new_var)
         {
-         if (debug_info_level > DINFO_LEVEL_TERSE
+         if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
              && !DECL_IGNORED_P (old_var)
              && nonlocalized_list)
            VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
@@ -705,6 +705,13 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
       gcc_assert (new_decl);
       /* Replace this variable with the copy.  */
       STRIP_TYPE_NOPS (new_decl);
+      /* ???  The C++ frontend uses void * pointer zero to initialize
+         any other type.  This confuses the middle-end type verification.
+        As cloned bodies do not go through gimplification again the fixup
+        there doesn't trigger.  */
+      if (TREE_CODE (new_decl) == INTEGER_CST
+         && !useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (new_decl)))
+       new_decl = fold_convert (TREE_TYPE (*tp), new_decl);
       *tp = new_decl;
       *walk_subtrees = 0;
     }
@@ -1297,6 +1304,14 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
   else
     walk_gimple_op (copy, remap_gimple_op_r, &wi); 
 
+  /* Clear the copied virtual operands.  We are not remapping them here
+     but are going to recreate them from scratch.  */
+  if (gimple_has_mem_ops (copy))
+    {
+      gimple_set_vdef (copy, NULL_TREE);
+      gimple_set_vuse (copy, NULL_TREE);
+    }
+
   /* We have to handle EH region remapping of GIMPLE_RESX specially because
      the region number is not an operand.  */
   if (gimple_code (stmt) == GIMPLE_RESX && id->eh_region_offset)
@@ -1378,6 +1393,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
         need to process all of them.  */
       do
        {
+         tree fn;
+
          stmt = gsi_stmt (copy_gsi);
          if (is_gimple_call (stmt)
              && gimple_call_va_arg_pack_p (stmt)
@@ -1466,34 +1483,24 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
             callgraph edges and update or duplicate them.  */
          if (is_gimple_call (stmt))
            {
-             struct cgraph_node *node;
-             struct cgraph_edge *edge;
+             struct cgraph_edge *edge = cgraph_edge (id->src_node, orig_stmt);
              int flags;
 
              switch (id->transform_call_graph_edges)
                {
              case CB_CGE_DUPLICATE:
-               edge = cgraph_edge (id->src_node, orig_stmt);
-               if (edge)
+               if (edge)
                  cgraph_clone_edge (edge, id->dst_node, stmt,
                                           REG_BR_PROB_BASE, 1,
                                           edge->frequency, true);
                break;
 
              case CB_CGE_MOVE_CLONES:
-               for (node = id->dst_node->next_clone;
-                   node;
-                   node = node->next_clone)
-                 {
-                   edge = cgraph_edge (node, orig_stmt);
-                         if (edge)
-                           cgraph_set_call_stmt (edge, stmt);
-                 }
-               /* FALLTHRU */
+               cgraph_set_call_stmt_including_clones (id->dst_node, orig_stmt, stmt);
+               break;
 
              case CB_CGE_MOVE:
-               edge = cgraph_edge (id->dst_node, orig_stmt);
-               if (edge)
+               if (edge)
                  cgraph_set_call_stmt (edge, stmt);
                break;
 
@@ -1501,6 +1508,37 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                gcc_unreachable ();
                }
 
+           /* Constant propagation on argument done during inlining
+              may create new direct call.  Produce an edge for it.  */
+           if (!edge && is_gimple_call (stmt)
+               && (fn = gimple_call_fndecl (stmt)) != NULL
+               && !cgraph_edge (id->dst_node, stmt))
+             {
+               struct cgraph_node *dest = cgraph_node (fn);
+
+               /* We have missing edge in the callgraph.  This can happen in one case
+                  where previous inlining turned indirect call into direct call by
+                  constant propagating arguments.  In all other cases we hit a bug
+                  (incorrect node sharing is most common reason for missing edges.  */
+               gcc_assert (dest->needed || !dest->analyzed);
+               if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
+                 cgraph_create_edge_including_clones (id->dst_node, dest, stmt,
+                                                      bb->count,
+                                                      compute_call_stmt_bb_frequency (id->dst_node->decl, bb),
+                                                      bb->loop_depth,
+                                                      CIF_ORIGINALLY_INDIRECT_CALL);
+               else
+                 cgraph_create_edge (id->dst_node, dest, stmt,
+                                     bb->count, CGRAPH_FREQ_BASE,
+                                     bb->loop_depth)->inline_failed
+                   = CIF_ORIGINALLY_INDIRECT_CALL;
+               if (dump_file)
+                 {
+                    fprintf (dump_file, "Created new direct edge to %s",
+                             cgraph_node_name (dest));
+                 }
+             }
+
              flags = gimple_call_flags (stmt);
 
              if (flags & ECF_MAY_BE_ALLOCA)
@@ -1600,8 +1638,6 @@ update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb,
        gimple phi;
        gimple_stmt_iterator si;
 
-       gcc_assert (e->flags & EDGE_ABNORMAL);
-
        if (!nonlocal_goto)
          gcc_assert (e->flags & EDGE_EH);
 
@@ -1617,7 +1653,8 @@ update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb,
            /* There shouldn't be any PHI nodes in the ENTRY_BLOCK.  */
            gcc_assert (!e->dest->aux);
 
-           gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)));
+           gcc_assert ((e->flags & EDGE_EH)
+                       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)));
 
            if (!is_gimple_reg (PHI_RESULT (phi)))
              {
@@ -2378,7 +2415,10 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
   STRIP_USELESS_TYPE_CONVERSION (use);
 
   if (DECL_BY_REFERENCE (result))
-    var = build_fold_addr_expr (var);
+    {
+      TREE_ADDRESSABLE (var) = 1;
+      var = build_fold_addr_expr (var);
+    }
 
  done:
   /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
@@ -2729,6 +2769,8 @@ estimate_move_cost (tree type)
 {
   HOST_WIDE_INT size;
 
+  gcc_assert (!VOID_TYPE_P (type));
+
   size = int_size_in_bytes (type);
 
   if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO (!optimize_size))
@@ -2741,7 +2783,8 @@ estimate_move_cost (tree type)
 /* Returns cost of operation CODE, according to WEIGHTS  */
 
 static int
-estimate_operator_cost (enum tree_code code, eni_weights *weights)
+estimate_operator_cost (enum tree_code code, eni_weights *weights,
+                       tree op1 ATTRIBUTE_UNUSED, tree op2)
 {
   switch (code)
     {
@@ -2851,7 +2894,9 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights)
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case RDIV_EXPR:
-      return weights->div_mod_cost;
+      if (TREE_CODE (op2) != INTEGER_CST)
+        return weights->div_mod_cost;
+      return 1;
 
     default:
       /* We expect a copy assignment with no operator.  */
@@ -2888,6 +2933,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
   unsigned cost, i;
   enum gimple_code code = gimple_code (stmt);
   tree lhs;
+  tree rhs;
 
   switch (code)
     {
@@ -2911,16 +2957,35 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
         of moving something into "a", which we compute using the function
         estimate_move_cost.  */
       lhs = gimple_assign_lhs (stmt);
+      rhs = gimple_assign_rhs1 (stmt);
+
+      /* EH magic stuff is most probably going to be optimized out.
+         We rarely really need to save EH info for unwinding
+         nested exceptions.  */
+      if (TREE_CODE (lhs) == FILTER_EXPR
+         || TREE_CODE (lhs) == EXC_PTR_EXPR
+          || TREE_CODE (rhs) == FILTER_EXPR
+         || TREE_CODE (rhs) == EXC_PTR_EXPR)
+       return 0;
       if (is_gimple_reg (lhs))
        cost = 0;
       else
        cost = estimate_move_cost (TREE_TYPE (lhs));
 
-      cost += estimate_operator_cost (gimple_assign_rhs_code (stmt), weights);
+      if (!is_gimple_reg (rhs) && !is_gimple_min_invariant (rhs))
+       cost += estimate_move_cost (TREE_TYPE (rhs));
+
+      cost += estimate_operator_cost (gimple_assign_rhs_code (stmt), weights,
+                                     gimple_assign_rhs1 (stmt),
+                                     get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
+                                     == GIMPLE_BINARY_RHS
+                                     ? gimple_assign_rhs2 (stmt) : NULL);
       break;
 
     case GIMPLE_COND:
-      cost = 1 + estimate_operator_cost (gimple_cond_code (stmt), weights);
+      cost = 1 + estimate_operator_cost (gimple_cond_code (stmt), weights,
+                                        gimple_op (stmt, 0),
+                                        gimple_op (stmt, 1));
       break;
 
     case GIMPLE_SWITCH:
@@ -2929,7 +2994,10 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
 
         TODO: once the switch expansion logic is sufficiently separated, we can
         do better job on estimating cost of the switch.  */
-      cost = gimple_switch_num_labels (stmt) * 2;
+      if (weights->time_based)
+        cost = floor_log2 (gimple_switch_num_labels (stmt)) * 2;
+      else
+        cost = gimple_switch_num_labels (stmt) * 2;
       break;
 
     case GIMPLE_CALL:
@@ -2952,8 +3020,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
            case BUILT_IN_CONSTANT_P:
              return 0;
            case BUILT_IN_EXPECT:
-             cost = 0;
-             break;
+             return 0;
 
            /* Prefetch instruction is not expensive.  */
            case BUILT_IN_PREFETCH:
@@ -2967,6 +3034,8 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
        if (decl)
          funtype = TREE_TYPE (decl);
 
+       if (!VOID_TYPE_P (TREE_TYPE (funtype)))
+         cost += estimate_move_cost (TREE_TYPE (funtype));
        /* Our cost must be kept in sync with
           cgraph_estimate_size_after_inlining that does use function
           declaration to figure out the arguments.  */
@@ -2974,20 +3043,24 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
          {
            tree arg;
            for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
-             cost += estimate_move_cost (TREE_TYPE (arg));
+             if (!VOID_TYPE_P (TREE_TYPE (arg)))
+               cost += estimate_move_cost (TREE_TYPE (arg));
          }
        else if (funtype && prototype_p (funtype))
          {
            tree t;
-           for (t = TYPE_ARG_TYPES (funtype); t; t = TREE_CHAIN (t))
-             cost += estimate_move_cost (TREE_VALUE (t));
+           for (t = TYPE_ARG_TYPES (funtype); t && t != void_list_node;
+                t = TREE_CHAIN (t))
+             if (!VOID_TYPE_P (TREE_VALUE (t)))
+               cost += estimate_move_cost (TREE_VALUE (t));
          }
        else
          {
            for (i = 0; i < gimple_call_num_args (stmt); i++)
              {
                tree arg = gimple_call_arg (stmt, i);
-               cost += estimate_move_cost (TREE_TYPE (arg));
+               if (!VOID_TYPE_P (TREE_TYPE (arg)))
+                 cost += estimate_move_cost (TREE_TYPE (arg));
              }
          }
 
@@ -2999,7 +3072,6 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
     case GIMPLE_NOP:
     case GIMPLE_PHI:
     case GIMPLE_RETURN:
-    case GIMPLE_CHANGE_DYNAMIC_TYPE:
     case GIMPLE_PREDICT:
       return 0;
 
@@ -3083,15 +3155,11 @@ estimate_num_insns_fn (tree fndecl, eni_weights *weights)
 void
 init_inline_once (void)
 {
-  eni_inlining_weights.call_cost = PARAM_VALUE (PARAM_INLINE_CALL_COST);
-  eni_inlining_weights.target_builtin_call_cost = 1;
-  eni_inlining_weights.div_mod_cost = 10;
-  eni_inlining_weights.omp_cost = 40;
-
   eni_size_weights.call_cost = 1;
   eni_size_weights.target_builtin_call_cost = 1;
   eni_size_weights.div_mod_cost = 1;
   eni_size_weights.omp_cost = 40;
+  eni_size_weights.time_based = false;
 
   /* Estimating time for call is difficult, since we have no idea what the
      called function does.  In the current uses of eni_time_weights,
@@ -3101,6 +3169,7 @@ init_inline_once (void)
   eni_time_weights.target_builtin_call_cost = 10;
   eni_time_weights.div_mod_cost = 10;
   eni_time_weights.omp_cost = 40;
+  eni_time_weights.time_based = true;
 }
 
 /* Estimate the number of instructions in a gimple_seq. */
@@ -3204,29 +3273,6 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 
   cg_edge = cgraph_edge (id->dst_node, stmt);
 
-  /* Constant propagation on argument done during previous inlining
-     may create new direct call.  Produce an edge for it.  */
-  if (!cg_edge)
-    {
-      struct cgraph_node *dest = cgraph_node (fn);
-
-      /* We have missing edge in the callgraph.  This can happen in one case
-         where previous inlining turned indirect call into direct call by
-         constant propagating arguments.  In all other cases we hit a bug
-         (incorrect node sharing is most common reason for missing edges.  */
-      gcc_assert (dest->needed);
-      cgraph_create_edge (id->dst_node, dest, stmt,
-                         bb->count, CGRAPH_FREQ_BASE,
-                         bb->loop_depth)->inline_failed
-       = CIF_ORIGINALLY_INDIRECT_CALL;
-      if (dump_file)
-       {
-          fprintf (dump_file, "Created new direct edge to %s",
-                   cgraph_node_name (dest));
-       }
-      goto egress;
-    }
-
   /* Don't try to inline functions that are not well-suited to
      inlining.  */
   if (!cgraph_inline_p (cg_edge, &reason))
@@ -3376,13 +3422,6 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   /* Declare the return variable for the function.  */
   retvar = declare_return_variable (id, return_slot, modify_dest, &use_retvar);
 
-  if (DECL_IS_OPERATOR_NEW (fn))
-    {
-      gcc_assert (TREE_CODE (retvar) == VAR_DECL
-                 && POINTER_TYPE_P (TREE_TYPE (retvar)));
-      DECL_NO_TBAA_P (retvar) = 1;
-    }
-
   /* Add local vars in this inlined callee to caller.  */
   t_step = id->src_cfun->local_decls;
   for (; t_step; t_step = TREE_CHAIN (t_step))
@@ -3406,10 +3445,20 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
      duplicate our body before altering anything.  */
   copy_body (id, bb->count, bb->frequency, bb, return_block);
 
+  /* Reset the escaped and callused solutions.  */
+  if (cfun->gimple_df)
+    {
+      pt_solution_reset (&cfun->gimple_df->escaped);
+      pt_solution_reset (&cfun->gimple_df->callused);
+    }
+
   /* Clean up.  */
   pointer_map_destroy (id->decl_map);
   id->decl_map = st;
 
+  /* Unlink the calls virtual operands before replacing it.  */
+  unlink_stmt_vdef (stmt);
+
   /* If the inlined function returns a result that we care about,
      substitute the GIMPLE_CALL with an assignment of the return
      variable to the LHS of the call.  That is, if STMT was
@@ -3420,10 +3469,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
       stmt = gimple_build_assign (gimple_call_lhs (stmt), use_retvar);
       gsi_replace (&stmt_gsi, stmt, false);
       if (gimple_in_ssa_p (cfun))
-       {
-          update_stmt (stmt);
-          mark_symbols_for_renaming (stmt);
-       }
+       mark_symbols_for_renaming (stmt);
       maybe_clean_or_replace_eh_stmt (old_stmt, stmt);
     }
   else
@@ -3443,7 +3489,6 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
                 undefined via a move.  */
              stmt = gimple_build_assign (gimple_call_lhs (stmt), def);
              gsi_replace (&stmt_gsi, stmt, true);
-             update_stmt (stmt);
            }
          else
            {
@@ -3528,6 +3573,7 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
          if (pointer_set_contains (statements, gsi_stmt (gsi)))
            {
              gimple old_stmt = gsi_stmt (gsi);
+             tree old_decl = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
 
              if (fold_stmt (&gsi))
                {
@@ -3536,8 +3582,9 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
                  gimple new_stmt = gsi_stmt (gsi);
                  update_stmt (new_stmt);
 
-                 if (is_gimple_call (old_stmt))
-                   cgraph_update_edges_for_call_stmt (old_stmt, new_stmt);
+                 if (is_gimple_call (old_stmt)
+                     || is_gimple_call (new_stmt))
+                   cgraph_update_edges_for_call_stmt (old_stmt, old_decl, new_stmt);
 
                  if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
                    gimple_purge_dead_eh_edges (BASIC_BLOCK (first));
@@ -3639,11 +3686,11 @@ optimize_inline_calls (tree fn)
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (fn);
 
-  /* We are not going to maintain the cgraph edges up to date.
-     Kill it so it won't confuse us.  */
-  cgraph_node_remove_callees (id.dst_node);
-
   fold_cond_expr_cond ();
+  delete_unreachable_blocks_update_callgraph (&id);
+#ifdef ENABLE_CHECKING
+  verify_cgraph_node (id.dst_node);
+#endif
 
   /* It would be nice to check SSA/CFG/statement consistency here, but it is
      not possible yet - the IPA passes might make various functions to not
@@ -4138,7 +4185,6 @@ copy_decl_to_var (tree decl, copy_body_data *id)
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
   DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl);
-  DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
 
   return copy_decl_for_dup_finish (id, decl, copy);
 }
@@ -4165,7 +4211,6 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
     {
       TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
       DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl);
-      DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (decl);
     }
 
   return copy_decl_for_dup_finish (id, decl, copy);
@@ -4269,27 +4314,98 @@ tree_versionable_function_p (tree fndecl)
   return true;
 }
 
-/* Create a new name for omp child function.  Returns an identifier.  */
+/* Delete all unreachable basic blocks and update callgraph.
+   Doing so is somewhat nontrivial because we need to update all clones and
+   remove inline function that become unreachable.  */
 
-static GTY(()) unsigned int clone_fn_id_num;
-
-static tree
-clone_function_name (tree decl)
+static bool
+delete_unreachable_blocks_update_callgraph (copy_body_data *id)
 {
-  tree name = DECL_ASSEMBLER_NAME (decl);
-  size_t len = IDENTIFIER_LENGTH (name);
-  char *tmp_name, *prefix;
-
-  prefix = XALLOCAVEC (char, len + strlen ("_clone") + 1);
-  memcpy (prefix, IDENTIFIER_POINTER (name), len);
-  strcpy (prefix + len, "_clone");
-#ifndef NO_DOT_IN_LABEL
-  prefix[len] = '.';
-#elif !defined NO_DOLLAR_IN_LABEL
-  prefix[len] = '$';
+  bool changed = false;
+  basic_block b, next_bb;
+
+  find_unreachable_blocks ();
+
+  /* Delete all unreachable basic blocks.  */
+
+  for (b = ENTRY_BLOCK_PTR->next_bb; b != EXIT_BLOCK_PTR; b = next_bb)
+    {
+      next_bb = b->next_bb;
+
+      if (!(b->flags & BB_REACHABLE))
+       {
+          gimple_stmt_iterator bsi;
+
+          for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next (&bsi))
+           if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL)
+             {
+               struct cgraph_edge *e;
+               struct cgraph_node *node;
+
+               if ((e = cgraph_edge (id->dst_node, gsi_stmt (bsi))) != NULL)
+                 {
+                   if (!e->inline_failed)
+                     cgraph_remove_node_and_inline_clones (e->callee);
+                   else
+                     cgraph_remove_edge (e);
+                 }
+               if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
+                   && id->dst_node->clones)
+                 for (node = id->dst_node->clones; node != id->dst_node;)
+                   {
+                     if ((e = cgraph_edge (node, gsi_stmt (bsi))) != NULL)
+                       {
+                         if (!e->inline_failed)
+                           cgraph_remove_node_and_inline_clones (e->callee);
+                         else
+                           cgraph_remove_edge (e);
+                       }
+                      
+                     if (node->clones)
+                       node = node->clones;
+                     else if (node->next_sibling_clone)
+                       node = node->next_sibling_clone;
+                     else
+                       {
+                         while (node != id->dst_node && !node->next_sibling_clone)
+                           node = node->clone_of;
+                         if (node != id->dst_node)
+                           node = node->next_sibling_clone;
+                       }
+                   }
+             }
+         delete_basic_block (b);
+         changed = true;
+       }
+    }
+
+  if (changed)
+    tidy_fallthru_edges ();
+#ifdef ENABLE_CHECKING0
+  verify_cgraph_node (id->dst_node);
+  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
+      && id->dst_node->clones)
+    {
+      struct cgraph_node *node;
+      for (node = id->dst_node->clones; node != id->dst_node;)
+       {
+         verify_cgraph_node (node);
+          
+         if (node->clones)
+           node = node->clones;
+         else if (node->next_sibling_clone)
+           node = node->next_sibling_clone;
+         else
+           {
+             while (node != id->dst_node && !node->next_sibling_clone)
+               node = node->clone_of;
+             if (node != id->dst_node)
+               node = node->next_sibling_clone;
+           }
+       }
+     }
 #endif
-  ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++);
-  return get_identifier (tmp_name);
+  return changed;
 }
 
 /* Create a copy of a function's tree.
@@ -4301,7 +4417,7 @@ clone_function_name (tree decl)
    trees. If UPDATE_CLONES is set, the call_stmt fields
    of edges of clones of the function will be updated.  */
 void
-tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
+tree_function_versioning (tree old_decl, tree new_decl, VEC(ipa_replace_map_p,gc)* tree_map,
                          bool update_clones, bitmap args_to_skip)
 {
   struct cgraph_node *old_version_node;
@@ -4337,13 +4453,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   memset (&id, 0, sizeof (id));
 
   /* Generate a new name for the new version. */
-  if (!update_clones)
-    {
-      DECL_NAME (new_decl) = clone_function_name (old_decl);
-      SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
-      SET_DECL_RTL (new_decl, NULL_RTX);
-      id.statements_to_fold = pointer_set_create ();
-    }
+  id.statements_to_fold = pointer_set_create ();
   
   id.decl_map = pointer_map_create ();
   id.src_fn = old_decl;
@@ -4376,11 +4486,10 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   
   /* If there's a tree_map, prepare for substitution.  */
   if (tree_map)
-    for (i = 0; i < VARRAY_ACTIVE_SIZE (tree_map); i++)
+    for (i = 0; i < VEC_length (ipa_replace_map_p, tree_map); i++)
       {
        gimple init;
-       replace_info
-         = (struct ipa_replace_map *) VARRAY_GENERIC_PTR (tree_map, i);
+       replace_info = VEC_index (ipa_replace_map_p, tree_map, i);
        if (replace_info->replace_p)
          {
            tree op = replace_info->new_tree;
@@ -4419,6 +4528,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   number_blocks (id.dst_fn);
   
   declare_inline_vars (DECL_INITIAL (new_decl), vars);
+
   if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
     /* Add local vars.  */
     for (t_step = DECL_STRUCT_FUNCTION (old_decl)->local_decls;
@@ -4455,28 +4565,17 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
 
   /* Clean up.  */
   pointer_map_destroy (id.decl_map);
-  if (!update_clones)
-    {
-      fold_marked_statements (0, id.statements_to_fold);
-      pointer_set_destroy (id.statements_to_fold);
-      fold_cond_expr_cond ();
-    }
-  if (gimple_in_ssa_p (cfun))
-    {
-      free_dominance_info (CDI_DOMINATORS);
-      free_dominance_info (CDI_POST_DOMINATORS);
-      if (!update_clones)
-        delete_unreachable_blocks ();
-      update_ssa (TODO_update_ssa);
-      if (!update_clones)
-       {
-         fold_cond_expr_cond ();
-         if (need_ssa_update_p ())
-           update_ssa (TODO_update_ssa);
-       }
-    }
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
+
+  fold_marked_statements (0, id.statements_to_fold);
+  pointer_set_destroy (id.statements_to_fold);
+  fold_cond_expr_cond ();
+  delete_unreachable_blocks_update_callgraph (&id);
+  update_ssa (TODO_update_ssa);
+  free_dominance_info (CDI_DOMINATORS);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
   VEC_free (gimple, heap, init_stmts);
   pop_cfun ();
   current_function_decl = old_current_function_decl;
@@ -4544,5 +4643,3 @@ tree_can_inline_p (tree caller, tree callee)
   /* Allow the backend to decide if inlining is ok.  */
   return targetm.target_option.can_inline_p (caller, callee);
 }
-
-#include "gt-tree-inline.h"