OSDN Git Service

2010-09-30 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index b241a21..b0627be 100644 (file)
@@ -23,7 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "toplev.h"
+#include "toplev.h" /* floor_log2 */
+#include "diagnostic-core.h"
 #include "tree.h"
 #include "tree-inline.h"
 #include "flags.h"
@@ -113,7 +114,7 @@ eni_weights eni_time_weights;
 
 /* Prototypes.  */
 
-static tree declare_return_variable (copy_body_data *, tree, tree);
+static tree declare_return_variable (copy_body_data *, tree, tree, basic_block);
 static void remap_block (tree *, copy_body_data *);
 static void copy_bind_expr (tree *, int *, copy_body_data *);
 static tree mark_local_for_remap_r (tree *, int *, void *);
@@ -234,6 +235,7 @@ remap_ssa_name (tree name, copy_body_data *id)
             regions of the CFG, but this is expensive to test.  */
          if (id->entry_bb
              && is_gimple_reg (SSA_NAME_VAR (name))
+             && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name)
              && TREE_CODE (SSA_NAME_VAR (name)) != PARM_DECL
              && (id->entry_bb != EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
                  || EDGE_COUNT (id->entry_bb->preds) != 1))
@@ -420,11 +422,11 @@ remap_type_1 (tree type, copy_body_data *id)
       {
        tree f, nf = NULL;
 
-       for (f = TYPE_FIELDS (new_tree); f ; f = TREE_CHAIN (f))
+       for (f = TYPE_FIELDS (new_tree); f ; f = DECL_CHAIN (f))
          {
            t = remap_decl (f, id);
            DECL_CONTEXT (t) = new_tree;
-           TREE_CHAIN (t) = nf;
+           DECL_CHAIN (t) = nf;
            nf = t;
          }
        TYPE_FIELDS (new_tree) = nreverse (nf);
@@ -535,7 +537,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
   tree new_decls = NULL_TREE;
 
   /* Remap its variables.  */
-  for (old_var = decls; old_var; old_var = TREE_CHAIN (old_var))
+  for (old_var = decls; old_var; old_var = DECL_CHAIN (old_var))
     {
       tree new_var;
 
@@ -544,8 +546,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
          if (TREE_CODE (old_var) == VAR_DECL
              && ! DECL_EXTERNAL (old_var)
              && (var_ann (old_var) || !gimple_in_ssa_p (cfun)))
-           cfun->local_decls = tree_cons (NULL_TREE, old_var,
-                                                  cfun->local_decls);
+           add_local_decl (cfun, old_var);
          if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
              && !DECL_IGNORED_P (old_var)
              && nonlocalized_list)
@@ -572,7 +573,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
       else
        {
          gcc_assert (DECL_P (new_var));
-         TREE_CHAIN (new_var) = new_decls;
+         DECL_CHAIN (new_var) = new_decls;
          new_decls = new_var;
  
          /* Also copy value-expressions.  */
@@ -810,48 +811,55 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
     {
       /* Otherwise, just copy the node.  Note that copy_tree_r already
         knows not to copy VAR_DECLs, etc., so this is safe.  */
-      if (TREE_CODE (*tp) == INDIRECT_REF)
+      if (TREE_CODE (*tp) == MEM_REF)
        {
-         /* Get rid of *& from inline substitutions that can happen when a
-            pointer argument is an ADDR_EXPR.  */
+         /* We need to re-canonicalize MEM_REFs from inline substitutions
+            that can happen when a pointer argument is an ADDR_EXPR.  */
          tree decl = TREE_OPERAND (*tp, 0);
          tree *n;
 
+          /* See remap_ssa_name.  */
+          if (TREE_CODE (decl) == SSA_NAME
+              && TREE_CODE (SSA_NAME_VAR (decl)) == RESULT_DECL
+              && id->transform_return_to_modify)
+            decl = SSA_NAME_VAR (decl);
+
          n = (tree *) pointer_map_contains (id->decl_map, decl);
          if (n)
            {
-             tree type, new_tree, old;
-
-             /* If we happen to get an ADDR_EXPR in n->value, strip
-                it manually here as we'll eventually get ADDR_EXPRs
-                which lie about their types pointed to.  In this case
-                build_fold_indirect_ref wouldn't strip the
-                INDIRECT_REF, but we absolutely rely on that.  As
-                fold_indirect_ref does other useful transformations,
-                try that first, though.  */
-             type = TREE_TYPE (TREE_TYPE (*n));
-             new_tree = unshare_expr (*n);
-             old = *tp;
-             *tp = gimple_fold_indirect_ref (new_tree);
-             if (!*tp)
-               {
-                 if (TREE_CODE (new_tree) == ADDR_EXPR)
-                   {
-                     *tp = fold_indirect_ref_1 (EXPR_LOCATION (new_tree),
-                                                type, new_tree);
-                     /* ???  We should either assert here or build
-                        a VIEW_CONVERT_EXPR instead of blindly leaking
-                        incompatible types to our IL.  */
-                     if (! *tp)
-                       *tp = TREE_OPERAND (new_tree, 0);
-                   }
-                 else
-                   {
-                     *tp = build1 (INDIRECT_REF, type, new_tree);
-                     TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
-                     TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
-                   }
+             tree old = *tp;
+             tree ptr = unshare_expr (*n);
+             tree tem;
+             if ((tem = maybe_fold_offset_to_reference (EXPR_LOCATION (*tp),
+                                                        ptr,
+                                                        TREE_OPERAND (*tp, 1),
+                                                        TREE_TYPE (*tp)))
+                 && TREE_THIS_VOLATILE (tem) == TREE_THIS_VOLATILE (old))
+               {
+                 tree *tem_basep = &tem;
+                 while (handled_component_p (*tem_basep))
+                   tem_basep = &TREE_OPERAND (*tem_basep, 0);
+                 if (TREE_CODE (*tem_basep) == MEM_REF)
+                   *tem_basep
+                     = build2 (MEM_REF, TREE_TYPE (*tem_basep),
+                               TREE_OPERAND (*tem_basep, 0),
+                               fold_convert (TREE_TYPE (TREE_OPERAND (*tp, 1)),
+                                             TREE_OPERAND (*tem_basep, 1)));
+                 else
+                   *tem_basep
+                     = build2 (MEM_REF, TREE_TYPE (*tem_basep),
+                               build_fold_addr_expr (*tem_basep),
+                               build_int_cst
+                                 (TREE_TYPE (TREE_OPERAND (*tp, 1)), 0));
+                 *tp = tem;
+               }
+             else
+               {
+                 *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp),
+                                    ptr, TREE_OPERAND (*tp, 1));
+                 TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
                }
+             TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
              *walk_subtrees = 0;
              return NULL;
            }
@@ -886,7 +894,7 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
       else if (TREE_CODE (*tp) == ADDR_EXPR)
        {
          /* Variable substitution need not be simple.  In particular,
-            the INDIRECT_REF substitution above.  Make sure that
+            the MEM_REF substitution above.  Make sure that
             TREE_CONSTANT and friends are up-to-date.  But make sure
             to not improperly set TREE_BLOCK on some sub-expressions.  */
          int invariant = is_gimple_min_invariant (*tp);
@@ -894,13 +902,7 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
          id->block = NULL_TREE;
          walk_tree (&TREE_OPERAND (*tp, 0), remap_gimple_op_r, data, NULL);
          id->block = block;
-
-         /* Handle the case where we substituted an INDIRECT_REF
-            into the operand of the ADDR_EXPR.  */
-         if (TREE_CODE (TREE_OPERAND (*tp, 0)) == INDIRECT_REF)
-           *tp = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0);
-         else
-           recompute_tree_invariant_for_addr_expr (*tp);
+         recompute_tree_invariant_for_addr_expr (*tp);
 
          /* If this used to be invariant, but is not any longer,
             then regimplification is probably needed.  */
@@ -1091,6 +1093,25 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
              return NULL;
            }
        }
+      else if (TREE_CODE (*tp) == MEM_REF)
+       {
+         /* We need to re-canonicalize MEM_REFs from inline substitutions
+            that can happen when a pointer argument is an ADDR_EXPR.  */
+         tree decl = TREE_OPERAND (*tp, 0);
+         tree *n;
+
+         n = (tree *) pointer_map_contains (id->decl_map, decl);
+         if (n)
+           {
+             tree old = *tp;
+             *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp),
+                                unshare_expr (*n), TREE_OPERAND (*tp, 1));
+             TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
+             TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+             *walk_subtrees = 0;
+             return NULL;
+           }
+       }
 
       /* Here is the "usual case".  Copy this tree node, and then
         tweak some special cases.  */
@@ -1221,7 +1242,10 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
         If RETVAL is just the result decl, the result decl has
         already been set (e.g. a recent "foo (&result_decl, ...)");
         just toss the entire GIMPLE_RETURN.  */
-      if (retval && TREE_CODE (retval) != RESULT_DECL)
+      if (retval
+         && (TREE_CODE (retval) != RESULT_DECL
+             && (TREE_CODE (retval) != SSA_NAME
+                 || TREE_CODE (SSA_NAME_VAR (retval)) != RESULT_DECL)))
         {
          copy = gimple_build_assign (id->retvar, retval);
          /* id->retvar is already substituted.  Skip it on later remapping.  */
@@ -1534,7 +1558,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
          tree new_rhs;
          new_rhs = force_gimple_operand_gsi (&seq_gsi,
                                              gimple_assign_rhs1 (stmt),
-                                             true, NULL, false, GSI_NEW_STMT);
+                                             true, NULL, false,
+                                             GSI_CONTINUE_LINKING);
          gimple_assign_set_rhs1 (stmt, new_rhs);
          id->regimplify = false;
        }
@@ -1571,7 +1596,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              size_t nargs = gimple_call_num_args (id->gimple_call);
              size_t n;
 
-             for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+             for (p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p))
                nargs--;
 
              /* Create the new array of arguments.  */
@@ -1604,7 +1629,6 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              gimple_call_set_lhs (new_call, gimple_call_lhs (stmt));
 
              gsi_replace (&copy_gsi, new_call, false);
-             gimple_set_bb (stmt, NULL);
              stmt = new_call;
            }
          else if (is_gimple_call (stmt)
@@ -1619,7 +1643,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              tree count, p;
              gimple new_stmt;
 
-             for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+             for (p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p))
                nargs--;
 
              count = build_int_cst (integer_type_node, nargs);
@@ -1713,12 +1737,13 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                  /* We have missing edge in the callgraph.  This can happen
                     when previous inlining turned an indirect call into a
                     direct call by constant propagating arguments or we are
-                    producing dead clone (for further clonning).  In all
+                    producing dead clone (for further cloning).  In all
                     other cases we hit a bug (incorrect node sharing is the
                     most common reason for missing edges).  */
                  gcc_assert (dest->needed || !dest->analyzed
                              || dest->address_taken
-                             || !id->src_node->analyzed);
+                             || !id->src_node->analyzed
+                             || !id->dst_node->analyzed);
                  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
                    cgraph_create_edge_including_clones
                      (id->dst_node, dest, orig_stmt, stmt, bb->count,
@@ -1953,12 +1978,13 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
   edge_iterator ei;
   gimple phi;
   gimple_stmt_iterator si;
+  edge new_edge;
+  bool inserted = false;
 
   for (si = gsi_start (phi_nodes (bb)); !gsi_end_p (si); gsi_next (&si))
     {
       tree res, new_res;
       gimple new_phi;
-      edge new_edge;
 
       phi = gsi_stmt (si);
       res = PHI_RESULT (phi);
@@ -1970,11 +1996,22 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
            = new_phi = create_phi_node (new_res, new_bb);
          FOR_EACH_EDGE (new_edge, ei, new_bb->preds)
            {
-             edge const old_edge
-               = find_edge ((basic_block) new_edge->src->aux, bb);
-             tree arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge);
-             tree new_arg = arg;
+             edge old_edge = find_edge ((basic_block) new_edge->src->aux, bb);
+             tree arg;
+             tree new_arg;
              tree block = id->block;
+             edge_iterator ei2;
+
+             /* When doing partial cloning, we allow PHIs on the entry block
+                as long as all the arguments are the same.  Find any input
+                edge to see argument to copy.  */
+             if (!old_edge)
+               FOR_EACH_EDGE (old_edge, ei2, bb->preds)
+                 if (!old_edge->src->aux)
+                   break;
+
+             arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge);
+             new_arg = arg;
              id->block = NULL_TREE;
              walk_tree (&new_arg, copy_tree_body_r, id, NULL);
              id->block = block;
@@ -1987,13 +2024,19 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
                {
                  gimple_seq stmts = NULL;
                  new_arg = force_gimple_operand (new_arg, &stmts, true, NULL);
-                 gsi_insert_seq_on_edge_immediate (new_edge, stmts);
+                 gsi_insert_seq_on_edge (new_edge, stmts);
+                 inserted = true;
                }
              add_phi_arg (new_phi, new_arg, new_edge,
                           gimple_phi_arg_location_from_edge (phi, old_edge));
            }
        }
     }
+
+  /* Commit the delayed edge insertions.  */
+  if (inserted)
+    FOR_EACH_EDGE (new_edge, ei, new_bb->preds)
+      gsi_commit_one_edge_insert (new_edge, NULL);
 }
 
 
@@ -2032,7 +2075,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count)
   gcc_assert (cfun->cfg == NULL);
   gcc_assert (cfun->decl == new_fndecl);
 
-  /* Copy items we preserve during clonning.  */
+  /* Copy items we preserve during cloning.  */
   cfun->static_chain_decl = src_cfun->static_chain_decl;
   cfun->nonlocal_goto_save_area = src_cfun->nonlocal_goto_save_area;
   cfun->function_end_locus = src_cfun->function_end_locus;
@@ -2149,6 +2192,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
   bool need_debug_cleanup = false;
   gcov_type count_scale;
   int last;
+  int incoming_frequency = 0;
+  gcov_type incoming_count = 0;
 
   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
     count_scale = (REG_BR_PROB_BASE * count
@@ -2159,6 +2204,28 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
   /* Register specific tree functions.  */
   gimple_register_cfg_hooks ();
 
+  /* If we are inlining just region of the function, make sure to connect new entry
+     to ENTRY_BLOCK_PTR.  Since new entry can be part of loop, we must compute
+     frequency and probability of ENTRY_BLOCK_PTR based on the frequencies and
+     probabilities of edges incoming from nonduplicated region.  */
+  if (new_entry)
+    {
+      edge e;
+      edge_iterator ei;
+
+      FOR_EACH_EDGE (e, ei, new_entry->preds)
+       if (!e->src->aux)
+         {
+           incoming_frequency += EDGE_FREQUENCY (e);
+           incoming_count += e->count;
+         }
+      incoming_count = incoming_count * count_scale / REG_BR_PROB_BASE;
+      incoming_frequency
+       = incoming_frequency * frequency_scale / REG_BR_PROB_BASE;
+      ENTRY_BLOCK_PTR->count = incoming_count;
+      ENTRY_BLOCK_PTR->frequency = incoming_frequency;
+    }
+
   /* Must have a CFG here at this point.  */
   gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
              (DECL_STRUCT_FUNCTION (callee_fndecl)));
@@ -2192,20 +2259,19 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
         || (bb->index > 0 && bitmap_bit_p (blocks_to_copy, bb->index)))
       need_debug_cleanup |= copy_edges_for_bb (bb, count_scale, exit_block_map);
 
+  if (new_entry)
+    {
+      edge e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU);
+      e->probability = REG_BR_PROB_BASE;
+      e->count = incoming_count;
+    }
+
   if (gimple_in_ssa_p (cfun))
     FOR_ALL_BB_FN (bb, cfun_to_copy)
       if (!blocks_to_copy
          || (bb->index > 0 && bitmap_bit_p (blocks_to_copy, bb->index)))
        copy_phis_for_bb (bb, id);
 
-  if (new_entry)
-    {
-      edge e;
-      e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU);
-      e->probability = REG_BR_PROB_BASE;
-      e->count = entry_block_map->count;
-    }
-
   FOR_ALL_BB_FN (bb, cfun_to_copy)
     if (bb->aux)
       {
@@ -2313,7 +2379,7 @@ copy_debug_stmts (copy_body_data *id)
   if (!id->debug_stmts)
     return;
 
-  for (i = 0; VEC_iterate (gimple, id->debug_stmts, i, stmt); i++)
+  FOR_EACH_VEC_ELT (gimple, id->debug_stmts, i, stmt)
     copy_debug_stmt (stmt, id);
 
   VEC_free (gimple, heap, id->debug_stmts);
@@ -2496,7 +2562,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
     }
 
   /* Declare this new variable.  */
-  TREE_CHAIN (var) = *vars;
+  DECL_CHAIN (var) = *vars;
   *vars = var;
 
   /* Make gimplifier happy about this variable.  */
@@ -2626,12 +2692,39 @@ initialize_inlined_parameters (copy_body_data *id, gimple stmt,
 
   /* Loop through the parameter declarations, replacing each with an
      equivalent VAR_DECL, appropriately initialized.  */
-  for (p = parms, i = 0; p; p = TREE_CHAIN (p), i++)
+  for (p = parms, i = 0; p; p = DECL_CHAIN (p), i++)
     {
       tree val;
       val = i < gimple_call_num_args (stmt) ? gimple_call_arg (stmt, i) : NULL;
       setup_one_parameter (id, p, val, fn, bb, &vars);
     }
+  /* After remapping parameters remap their types.  This has to be done
+     in a second loop over all parameters to appropriately remap
+     variable sized arrays when the size is specified in a
+     parameter following the array.  */
+  for (p = parms, i = 0; p; p = DECL_CHAIN (p), i++)
+    {
+      tree *varp = (tree *) pointer_map_contains (id->decl_map, p);
+      if (varp
+         && TREE_CODE (*varp) == VAR_DECL)
+       {
+         tree def = (gimple_in_ssa_p (cfun) && is_gimple_reg (p)
+                     ? gimple_default_def (id->src_cfun, p) : NULL);
+         tree var = *varp;
+         TREE_TYPE (var) = remap_type (TREE_TYPE (var), id);
+         /* Also remap the default definition if it was remapped
+            to the default definition of the parameter replacement
+            by the parameter setup.  */
+         if (def)
+           {
+             tree *defp = (tree *) pointer_map_contains (id->decl_map, def);
+             if (defp
+                 && TREE_CODE (*defp) == SSA_NAME
+                 && SSA_NAME_VAR (*defp) == var)
+               TREE_TYPE (*defp) = TREE_TYPE (var);
+           }
+       }
+    }
 
   /* Initialize the static chain.  */
   p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
@@ -2661,7 +2754,8 @@ initialize_inlined_parameters (copy_body_data *id, gimple stmt,
    as seen by the caller.  */
 
 static tree
-declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest)
+declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
+                        basic_block entry_bb)
 {
   tree callee = id->src_fn;
   tree caller = id->dst_fn;
@@ -2779,9 +2873,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest)
     }
 
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
-  DECL_STRUCT_FUNCTION (caller)->local_decls
-    = tree_cons (NULL_TREE, var,
-                DECL_STRUCT_FUNCTION (caller)->local_decls);
+  add_local_decl (DECL_STRUCT_FUNCTION (caller), var);
 
   /* Do not have the rest of GCC warn about this variable as it should
      not be visible to the user.  */
@@ -2806,8 +2898,28 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest)
  done:
   /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
      way, when the RESULT_DECL is encountered, it will be
-     automatically replaced by the VAR_DECL.  */
-  insert_decl_map (id, result, var);
+     automatically replaced by the VAR_DECL.  
+
+     When returning by reference, ensure that RESULT_DECL remaps to
+     gimple_val.  */
+  if (DECL_BY_REFERENCE (result)
+      && !is_gimple_val (var))
+    {
+      tree temp = create_tmp_var (TREE_TYPE (result), "retvalptr");
+      if (gimple_in_ssa_p (id->src_cfun))
+       {
+         get_var_ann (temp);
+         add_referenced_var (temp);
+       }
+      insert_decl_map (id, result, temp);
+      /* When RESULT_DECL is in SSA form, we need to use it's default_def
+        SSA_NAME.  */
+      if (gimple_in_ssa_p (id->src_cfun) && gimple_default_def (id->src_cfun, result))
+        temp = remap_ssa_name (gimple_default_def (id->src_cfun, result), id);
+      insert_init_stmt (id, entry_bb, gimple_build_assign (temp, var));
+    }
+  else
+    insert_decl_map (id, result, var);
 
   /* Remember this so we can ignore it in remap_decls.  */
   id->retvar = var;
@@ -2840,7 +2952,8 @@ static const char *
 copy_forbidden (struct function *fun, tree fndecl)
 {
   const char *reason = fun->cannot_be_copied_reason;
-  tree step;
+  tree decl;
+  unsigned ix;
 
   /* Only examine the function once.  */
   if (fun->cannot_be_copied_set)
@@ -2859,23 +2972,19 @@ copy_forbidden (struct function *fun, tree fndecl)
       goto fail;
     }
 
-  for (step = fun->local_decls; step; step = TREE_CHAIN (step))
-    {
-      tree decl = TREE_VALUE (step);
-
-      if (TREE_CODE (decl) == VAR_DECL
-         && TREE_STATIC (decl)
-         && !DECL_EXTERNAL (decl)
-         && DECL_INITIAL (decl)
-         && walk_tree_without_duplicates (&DECL_INITIAL (decl),
-                                          has_label_address_in_static_1,
-                                          fndecl))
-       {
-         reason = G_("function %q+F can never be copied because it saves "
-                     "address of local label in a static variable");
-         goto fail;
-       }
-    }
+  FOR_EACH_LOCAL_DECL (fun, ix, decl)
+    if (TREE_CODE (decl) == VAR_DECL
+       && TREE_STATIC (decl)
+       && !DECL_EXTERNAL (decl)
+       && DECL_INITIAL (decl)
+       && walk_tree_without_duplicates (&DECL_INITIAL (decl),
+                                        has_label_address_in_static_1,
+                                        fndecl))
+      {
+       reason = G_("function %q+F can never be copied because it saves "
+                   "address of local label in a static variable");
+       goto fail;
+      }
 
  fail:
   fun->cannot_be_copied_reason = reason;
@@ -3097,12 +3206,6 @@ tree_inlinable_function_p (tree fn)
       inlinable = false;
     }
 
-  /* Don't auto-inline anything that might not be bound within
-     this unit of translation.  */
-  else if (!DECL_DECLARED_INLINE_P (fn)
-          && DECL_REPLACEABLE_P (fn))
-    inlinable = false;
-
   else if (!function_attribute_inlinable_p (fn))
     {
       if (do_warning)
@@ -3239,6 +3342,8 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights,
     case WIDEN_SUM_EXPR:
     case WIDEN_MULT_EXPR:
     case DOT_PROD_EXPR:
+    case WIDEN_MULT_PLUS_EXPR:
+    case WIDEN_MULT_MINUS_EXPR:
 
     case VEC_WIDEN_MULT_HI_EXPR:
     case VEC_WIDEN_MULT_LO_EXPR:
@@ -3376,105 +3481,13 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
        if (POINTER_TYPE_P (funtype))
          funtype = TREE_TYPE (funtype);
 
-       if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
+       if (is_simple_builtin (decl))
+         return 0;
+       else if (is_inexpensive_builtin (decl))
          cost = weights->target_builtin_call_cost;
        else
          cost = weights->call_cost;
 
-       if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
-         switch (DECL_FUNCTION_CODE (decl))
-           {
-           /* Builtins that expand to constants.  */
-           case BUILT_IN_CONSTANT_P:
-           case BUILT_IN_EXPECT:
-           case BUILT_IN_OBJECT_SIZE:
-           case BUILT_IN_UNREACHABLE:
-           /* Simple register moves or loads from stack.  */
-           case BUILT_IN_RETURN_ADDRESS:
-           case BUILT_IN_EXTRACT_RETURN_ADDR:
-           case BUILT_IN_FROB_RETURN_ADDR:
-           case BUILT_IN_RETURN:
-           case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
-           case BUILT_IN_FRAME_ADDRESS:
-           case BUILT_IN_VA_END:
-           case BUILT_IN_STACK_SAVE:
-           case BUILT_IN_STACK_RESTORE:
-           /* Exception state returns or moves registers around.  */
-           case BUILT_IN_EH_FILTER:
-           case BUILT_IN_EH_POINTER:
-           case BUILT_IN_EH_COPY_VALUES:
-             return 0;
-
-           /* builtins that are not expensive (that is they are most probably
-              expanded inline into resonably simple code).  */
-           case BUILT_IN_ABS:
-           case BUILT_IN_ALLOCA:
-           case BUILT_IN_BSWAP32:
-           case BUILT_IN_BSWAP64:
-           case BUILT_IN_CLZ:
-           case BUILT_IN_CLZIMAX:
-           case BUILT_IN_CLZL:
-           case BUILT_IN_CLZLL:
-           case BUILT_IN_CTZ:
-           case BUILT_IN_CTZIMAX:
-           case BUILT_IN_CTZL:
-           case BUILT_IN_CTZLL:
-           case BUILT_IN_FFS:
-           case BUILT_IN_FFSIMAX:
-           case BUILT_IN_FFSL:
-           case BUILT_IN_FFSLL:
-           case BUILT_IN_IMAXABS:
-           case BUILT_IN_FINITE:
-           case BUILT_IN_FINITEF:
-           case BUILT_IN_FINITEL:
-           case BUILT_IN_FINITED32:
-           case BUILT_IN_FINITED64:
-           case BUILT_IN_FINITED128:
-           case BUILT_IN_FPCLASSIFY:
-           case BUILT_IN_ISFINITE:
-           case BUILT_IN_ISINF_SIGN:
-           case BUILT_IN_ISINF:
-           case BUILT_IN_ISINFF:
-           case BUILT_IN_ISINFL:
-           case BUILT_IN_ISINFD32:
-           case BUILT_IN_ISINFD64:
-           case BUILT_IN_ISINFD128:
-           case BUILT_IN_ISNAN:
-           case BUILT_IN_ISNANF:
-           case BUILT_IN_ISNANL:
-           case BUILT_IN_ISNAND32:
-           case BUILT_IN_ISNAND64:
-           case BUILT_IN_ISNAND128:
-           case BUILT_IN_ISNORMAL:
-           case BUILT_IN_ISGREATER:
-           case BUILT_IN_ISGREATEREQUAL:
-           case BUILT_IN_ISLESS:
-           case BUILT_IN_ISLESSEQUAL:
-           case BUILT_IN_ISLESSGREATER:
-           case BUILT_IN_ISUNORDERED:
-           case BUILT_IN_VA_ARG_PACK:
-           case BUILT_IN_VA_ARG_PACK_LEN:
-           case BUILT_IN_VA_COPY:
-           case BUILT_IN_TRAP:
-           case BUILT_IN_SAVEREGS:
-           case BUILT_IN_POPCOUNTL:
-           case BUILT_IN_POPCOUNTLL:
-           case BUILT_IN_POPCOUNTIMAX:
-           case BUILT_IN_POPCOUNT:
-           case BUILT_IN_PARITYL:
-           case BUILT_IN_PARITYLL:
-           case BUILT_IN_PARITYIMAX:
-           case BUILT_IN_PARITY:
-           case BUILT_IN_LABS:
-           case BUILT_IN_LLABS:
-           case BUILT_IN_PREFETCH:
-             cost = weights->target_builtin_call_cost;
-             break;
-
-           default:
-             break;
-           }
-
        if (decl)
          funtype = TREE_TYPE (decl);
 
@@ -3495,7 +3508,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
        if (decl && DECL_ARGUMENTS (decl) && !stdarg)
          {
            tree arg;
-           for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
+           for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
              if (!VOID_TYPE_P (TREE_TYPE (arg)))
                cost += estimate_move_cost (TREE_TYPE (arg));
          }
@@ -3660,18 +3673,41 @@ prepend_lexical_block (tree current_block, tree new_block)
   BLOCK_SUPERCONTEXT (new_block) = current_block;
 }
 
-/* Fetch callee declaration from the call graph edge going from NODE and
-   associated with STMR call statement.  Return NULL_TREE if not found.  */
-static tree
-get_indirect_callee_fndecl (struct cgraph_node *node, gimple stmt)
+/* Add local variables from CALLEE to CALLER.  */
+
+static inline void
+add_local_variables (struct function *callee, struct function *caller,
+                    copy_body_data *id, bool check_var_ann)
 {
-  struct cgraph_edge *cs;
+  tree var;
+  unsigned ix;
 
-  cs = cgraph_edge (node, stmt);
-  if (cs && !cs->indirect_unknown_callee)
-    return cs->callee->decl;
+  FOR_EACH_LOCAL_DECL (callee, ix, var)
+    if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
+      {
+       if (!check_var_ann
+           || (var_ann (var) && add_referenced_var (var)))
+         add_local_decl (caller, var);
+      }
+    else if (!can_be_nonlocal (var, id))
+      {
+        tree new_var = remap_decl (var, id);
 
-  return NULL_TREE;
+        /* Remap debug-expressions.  */
+       if (TREE_CODE (new_var) == VAR_DECL
+           && DECL_DEBUG_EXPR_IS_FROM (new_var)
+           && new_var != var)
+         {
+           tree tem = DECL_DEBUG_EXPR (var);
+           bool old_regimplify = id->regimplify;
+           id->remapping_type_depth++;
+           walk_tree (&tem, copy_tree_body_r, id, NULL);
+           id->remapping_type_depth--;
+           id->regimplify = old_regimplify;
+           SET_DECL_DEBUG_EXPR (new_var, tem);
+         }
+       add_local_decl (caller, new_var);
+      }
 }
 
 /* If STMT is a GIMPLE_CALL, replace it with its inline expansion.  */
@@ -3692,8 +3728,6 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   gimple_stmt_iterator gsi, stmt_gsi;
   bool successfully_inlined = FALSE;
   bool purge_dead_abnormal_edges;
-  tree t_step;
-  tree var;
 
   /* Set input_location here so we get the right instantiation context
      if we call instantiate_decl from inlinable_function_p.  */
@@ -3709,11 +3743,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
      If we cannot, then there is no hope of inlining the function.  */
   fn = gimple_call_fndecl (stmt);
   if (!fn)
-    {
-      fn = get_indirect_callee_fndecl (id->dst_node, stmt);
-      if (!fn)
-       goto egress;
-    }
+    goto egress;
 
   /* Turn forward declarations into real ones.  */
   fn = cgraph_node (fn)->decl;
@@ -3894,23 +3924,10 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
     }
 
   /* Declare the return variable for the function.  */
-  use_retvar = declare_return_variable (id, return_slot, modify_dest);
+  use_retvar = declare_return_variable (id, return_slot, modify_dest, bb);
 
   /* 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))
-    {
-      var = TREE_VALUE (t_step);
-      if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
-       {
-         if (var_ann (var) && add_referenced_var (var))
-           cfun->local_decls = tree_cons (NULL_TREE, var,
-                                          cfun->local_decls);
-       }
-      else if (!can_be_nonlocal (var, id))
-       cfun->local_decls = tree_cons (NULL_TREE, remap_decl (var, id),
-                                      cfun->local_decls);
-    }
+  add_local_variables (id->src_cfun, cfun, id, true);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -4021,7 +4038,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 
 /* Expand call statements reachable from STMT_P.
    We can only have CALL_EXPRs as the "toplevel" tree code or nested
-   in a MODIFY_EXPR.  See tree-gimple.c:get_call_expr_in().  We can
+   in a MODIFY_EXPR.  See gimple.c:get_call_expr_in().  We can
    unfortunately not use that function here because we need a pointer
    to the CALL_EXPR, not the tree itself.  */
 
@@ -4146,6 +4163,7 @@ optimize_inline_calls (tree fn)
   basic_block bb;
   int last = n_basic_blocks;
   struct gimplify_ctx gctx;
+  bool inlined_p = false;
 
   /* There is no point in performing inlining if errors have already
      occurred -- and we might crash if we try to inline invalid
@@ -4185,7 +4203,7 @@ optimize_inline_calls (tree fn)
      follow it; we'll trudge through them, processing their CALL_EXPRs
      along the way.  */
   FOR_EACH_BB (bb)
-    gimple_expand_calls_inline (bb, &id);
+    inlined_p |= gimple_expand_calls_inline (bb, &id);
 
   pop_gimplify_context (NULL);
 
@@ -4201,18 +4219,19 @@ optimize_inline_calls (tree fn)
     }
 #endif
 
-  /* Fold the statements before compacting/renumbering the basic blocks.  */
+  /* Fold queued statements.  */
   fold_marked_statements (last, id.statements_to_fold);
   pointer_set_destroy (id.statements_to_fold);
 
   gcc_assert (!id.debug_stmts);
 
-  /* Renumber the (code) basic_blocks consecutively.  */
-  compact_blocks ();
+  /* If we didn't inline into the function there is nothing to do.  */
+  if (!inlined_p)
+    return 0;
+
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (fn);
 
-  fold_cond_expr_cond ();
   delete_unreachable_blocks_update_callgraph (&id);
 #ifdef ENABLE_CHECKING
   verify_cgraph_node (id.dst_node);
@@ -4225,6 +4244,7 @@ optimize_inline_calls (tree fn)
   return (TODO_update_ssa
          | TODO_cleanup_cfg
          | (gimple_in_ssa_p (cfun) ? TODO_remove_unused_locals : 0)
+         | (gimple_in_ssa_p (cfun) ? TODO_update_address_taken : 0)
          | (profile_status != PROFILE_ABSENT ? TODO_rebuild_frequencies : 0));
 }
 
@@ -4648,11 +4668,11 @@ static void
 declare_inline_vars (tree block, tree vars)
 {
   tree t;
-  for (t = vars; t; t = TREE_CHAIN (t))
+  for (t = vars; t; t = DECL_CHAIN (t))
     {
       DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
       gcc_assert (!TREE_STATIC (t) && !TREE_ASM_WRITTEN (t));
-      cfun->local_decls = tree_cons (NULL_TREE, t, cfun->local_decls);
+      add_local_decl (cfun, t);
     }
 
   if (block)
@@ -4797,13 +4817,13 @@ copy_arguments_for_versioning (tree orig_parm, copy_body_data * id,
 
   parg = &new_parm;
 
-  for (arg = orig_parm; arg; arg = TREE_CHAIN (arg), i++)
+  for (arg = orig_parm; arg; arg = DECL_CHAIN (arg), i++)
     if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
       {
         tree new_tree = remap_decl (arg, id);
         lang_hooks.dup_lang_specific_decl (new_tree);
         *parg = new_tree;
-       parg = &TREE_CHAIN (new_tree);
+       parg = &DECL_CHAIN (new_tree);
       }
     else if (!pointer_map_contains (id->decl_map, arg))
       {
@@ -4815,7 +4835,7 @@ copy_arguments_for_versioning (tree orig_parm, copy_body_data * id,
        add_referenced_var (var);
        insert_decl_map (id, arg, var);
         /* Declare this new variable.  */
-        TREE_CHAIN (var) = *vars;
+        DECL_CHAIN (var) = *vars;
         *vars = var;
       }
   return new_parm;
@@ -4828,11 +4848,11 @@ copy_static_chain (tree static_chain, copy_body_data * id)
   tree *chain_copy, *pvar;
 
   chain_copy = &static_chain;
-  for (pvar = chain_copy; *pvar; pvar = &TREE_CHAIN (*pvar))
+  for (pvar = chain_copy; *pvar; pvar = &DECL_CHAIN (*pvar))
     {
       tree new_tree = remap_decl (*pvar, id);
       lang_hooks.dup_lang_specific_decl (new_tree);
-      TREE_CHAIN (new_tree) = TREE_CHAIN (*pvar);
+      DECL_CHAIN (new_tree) = DECL_CHAIN (*pvar);
       *pvar = new_tree;
     }
   return static_chain;
@@ -4983,7 +5003,6 @@ tree_function_versioning (tree old_decl, tree new_decl,
   basic_block old_entry_block, bb;
   VEC (gimple, heap) *init_stmts = VEC_alloc (gimple, heap, 10);
 
-  tree t_step;
   tree old_current_function_decl = current_function_decl;
   tree vars = NULL_TREE;
 
@@ -5067,7 +5086,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
              {
                int i = replace_info->parm_num;
                tree parm;
-               for (parm = DECL_ARGUMENTS (old_decl); i; parm = TREE_CHAIN (parm))
+               for (parm = DECL_ARGUMENTS (old_decl); i; parm = DECL_CHAIN (parm))
                  i --;
                replace_info->old_tree = parm;
              }
@@ -5103,24 +5122,11 @@ tree_function_versioning (tree old_decl, tree new_decl,
 
   DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
 
-  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
-  number_blocks (id.dst_fn);
-
   declare_inline_vars (DECL_INITIAL (new_decl), vars);
 
-  if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
+  if (!VEC_empty (tree, DECL_STRUCT_FUNCTION (old_decl)->local_decls))
     /* Add local vars.  */
-    for (t_step = DECL_STRUCT_FUNCTION (old_decl)->local_decls;
-        t_step; t_step = TREE_CHAIN (t_step))
-      {
-       tree var = TREE_VALUE (t_step);
-       if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
-         cfun->local_decls = tree_cons (NULL_TREE, var, cfun->local_decls);
-       else if (!can_be_nonlocal (var, &id))
-         cfun->local_decls =
-           tree_cons (NULL_TREE, remap_decl (var, &id),
-                      cfun->local_decls);
-      }
+    add_local_variables (DECL_STRUCT_FUNCTION (old_decl), cfun, &id, false);
 
   /* Copy the Function's body.  */
   copy_body (&id, old_entry_block->count, REG_BR_PROB_BASE,
@@ -5168,6 +5174,31 @@ tree_function_versioning (tree old_decl, tree new_decl,
   if (id.dst_node->analyzed)
     cgraph_rebuild_references ();
   update_ssa (TODO_update_ssa);
+
+  /* After partial cloning we need to rescale frequencies, so they are
+     within proper range in the cloned function.  */
+  if (new_entry)
+    {
+      struct cgraph_edge *e;
+      rebuild_frequencies ();
+
+      new_version_node->count = ENTRY_BLOCK_PTR->count;
+      for (e = new_version_node->callees; e; e = e->next_callee)
+       {
+         basic_block bb = gimple_bb (e->call_stmt);
+         e->frequency = compute_call_stmt_bb_frequency (current_function_decl,
+                                                        bb);
+         e->count = bb->count;
+       }
+      for (e = new_version_node->indirect_calls; e; e = e->next_callee)
+       {
+         basic_block bb = gimple_bb (e->call_stmt);
+         e->frequency = compute_call_stmt_bb_frequency (current_function_decl,
+                                                        bb);
+         e->count = bb->count;
+       }
+    }
+
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
 
@@ -5199,7 +5230,7 @@ maybe_inline_call_in_expr (tree exp)
       /* Remap the parameters.  */
       for (param = DECL_ARGUMENTS (fn), arg = first_call_expr_arg (exp, &iter);
           param;
-          param = TREE_CHAIN (param), arg = next_call_expr_arg (&iter))
+          param = DECL_CHAIN (param), arg = next_call_expr_arg (&iter))
        *pointer_map_insert (decl_map, param) = arg;
 
       memset (&id, 0, sizeof (id));