OSDN Git Service

* ipa-cp.c (ipcp_read_summary): Remove now invalid FIXME and
[pf3gnuchains/gcc-fork.git] / gcc / ipa-cp.c
index 8077432..79ff16e 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural constant propagation
-   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Razya Ladelsky <RAZYA@il.ibm.com>
    
 This file is part of GCC.
@@ -99,7 +99,7 @@ along with GCC; see the file COPYING3.  If not see
    2. For read-only parameters that do not live in memory, we replace all their
       uses with the constant.
 
-   We also need to modify some callsites to call the cloned functiosns instead
+   We also need to modify some callsites to call the cloned functions instead
    of the original ones.  For a callsite passing an argument found to be a
    constant by IPCP, there are two different cases to handle:
    1. A constant is passed as an argument.  In this case the callsite in the
@@ -109,7 +109,7 @@ along with GCC; see the file COPYING3.  If not see
       only the callsite in the cloned caller is redirected to call to the
       cloned callee.
 
-   This update is done in two steps: First all cloned functionss are created
+   This update is done in two steps: First all cloned functions are created
    during a traversal of the call graph, during which all callsites are
    redirected to call the cloned function.  Then the callsites are traversed
    and many calls redirected back to fit the description above.
@@ -132,6 +132,23 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "tree-dump.h"
 #include "tree-inline.h"
+#include "fibheap.h"
+#include "params.h"
+
+/* Number of functions identified as candidates for cloning. When not cloning
+   we can simplify iterate stage not forcing it to go through the decision
+   on what is profitable and what not.  */
+static int n_cloning_candidates;
+
+/* Maximal count found in program.  */
+static gcov_type max_count;
+
+/* Cgraph nodes that has been completely replaced by cloning during iterate
+ * stage and will be removed after ipcp is finished.  */
+static bitmap dead_nodes;
+
+static void ipcp_print_profile_data (FILE *);
+static void ipcp_function_scale_print (FILE *);
 
 /* Get the original node field of ipa_node_params associated with node NODE.  */
 static inline struct cgraph_node *
@@ -153,10 +170,20 @@ static void
 ipcp_init_cloned_node (struct cgraph_node *orig_node,
                       struct cgraph_node *new_node)
 {
-  ipa_create_node_params (new_node);
+  ipa_check_create_node_params ();
+  ipa_initialize_node_params (new_node);
   IPA_NODE_REF (new_node)->ipcp_orig_node = orig_node;
-  ipa_count_formal_params (new_node);
-  ipa_create_param_decls_array (new_node);
+}
+
+/* Perform intraprocedrual analysis needed for ipcp.  */
+static void
+ipcp_analyze_node (struct cgraph_node *node)
+{
+  /* Unreachable nodes should have been eliminated before ipcp.  */
+  gcc_assert (node->needed || node->reachable);
+
+  ipa_initialize_node_params (node);
+  ipa_detect_param_modifications (node);
 }
 
 /* Return scale for NODE.  */
@@ -177,12 +204,20 @@ ipcp_set_node_scale (struct cgraph_node *node, gcov_type count)
 static inline bool
 ipcp_lat_is_const (struct ipcp_lattice *lat)
 {
-  if (lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
+  if (lat->type == IPA_CONST_VALUE)
     return true;
   else
     return false;
 }
 
+/* Return whether LAT is a constant lattice that ipa-cp can actually insert
+   into the code (i.e. constants excluding member pointers and pointers).  */
+static inline bool
+ipcp_lat_is_insertable (struct ipcp_lattice *lat)
+{
+  return lat->type == IPA_CONST_VALUE;
+}
+
 /* Return true if LAT1 and LAT2 are equal.  */
 static inline bool
 ipcp_lats_are_equal (struct ipcp_lattice *lat1, struct ipcp_lattice *lat2)
@@ -235,9 +270,9 @@ ipa_lattice_meet (struct ipcp_lattice *res, struct ipcp_lattice *lat1,
 /* Return the lattice corresponding to the Ith formal parameter of the function
    described by INFO.  */
 static inline struct ipcp_lattice *
-ipcp_get_ith_lattice (struct ipa_node_params *info, int i)
+ipcp_get_lattice (struct ipa_node_params *info, int i)
 {
-  return &(info->ipcp_lattices[i]);
+  return &(info->params[i].ipcp_lattice);
 }
 
 /* Given the jump function JFUNC, compute the lattice LAT that describes the
@@ -247,37 +282,80 @@ static void
 ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
                         struct ipa_jump_func *jfunc)
 {
-  if (jfunc->type == IPA_UNKNOWN)
-    lat->type = IPA_BOTTOM;
-  else if (jfunc->type == IPA_CONST)
+  if (jfunc->type == IPA_JF_CONST)
     {
       lat->type = IPA_CONST_VALUE;
       lat->constant = jfunc->value.constant;
     }
-  else if (jfunc->type == IPA_CONST_REF)
+  else if (jfunc->type == IPA_JF_PASS_THROUGH)
     {
-      lat->type = IPA_CONST_VALUE_REF;
-      lat->constant = jfunc->value.constant;
+      struct ipcp_lattice *caller_lat;
+      tree cst;
+
+      caller_lat = ipcp_get_lattice (info, jfunc->value.pass_through.formal_id);
+      lat->type = caller_lat->type;
+      if (caller_lat->type != IPA_CONST_VALUE)
+       return;
+      cst = caller_lat->constant;
+
+      if (jfunc->value.pass_through.operation != NOP_EXPR)
+       {
+         tree restype;
+         if (TREE_CODE_CLASS (jfunc->value.pass_through.operation)
+             == tcc_comparison)
+           restype = boolean_type_node;
+         else
+           restype = TREE_TYPE (cst);
+         cst = fold_binary (jfunc->value.pass_through.operation,
+                            restype, cst, jfunc->value.pass_through.operand);
+       }
+      if (!cst || !is_gimple_ip_invariant (cst))
+       lat->type = IPA_BOTTOM;
+      lat->constant = cst;
     }
-  else if (jfunc->type == IPA_PASS_THROUGH)
+  else if (jfunc->type == IPA_JF_ANCESTOR)
     {
       struct ipcp_lattice *caller_lat;
+      tree t;
+      bool ok;
 
-      caller_lat = ipcp_get_ith_lattice (info, jfunc->value.formal_id);
+      caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id);
       lat->type = caller_lat->type;
-      lat->constant = caller_lat->constant;
+      if (caller_lat->type != IPA_CONST_VALUE)
+       return;
+      if (TREE_CODE (caller_lat->constant) != ADDR_EXPR)
+       {
+         /* This can happen when the constant is a NULL pointer.  */
+         lat->type = IPA_BOTTOM;
+         return;
+       }
+      t = TREE_OPERAND (caller_lat->constant, 0);
+      ok = build_ref_for_offset (&t, TREE_TYPE (t),
+                                jfunc->value.ancestor.offset,
+                                jfunc->value.ancestor.type, false);
+      if (!ok)
+       {
+         lat->type = IPA_BOTTOM;
+         lat->constant = NULL_TREE;
+       }
+      else
+       lat->constant = build_fold_addr_expr (t);
     }
+  else
+    lat->type = IPA_BOTTOM;
 }
 
-/* True when OLD and NEW values are not the same.  */
+/* True when OLD_LAT and NEW_LAT values are not the same.  */
+
 static bool
-ipcp_lattice_changed (struct ipcp_lattice *old, struct ipcp_lattice *new)
+ipcp_lattice_changed (struct ipcp_lattice *old_lat,
+                     struct ipcp_lattice *new_lat)
 {
-  if (old->type == new->type)
+  if (old_lat->type == new_lat->type)
     {
-      if (!ipcp_lat_is_const (old))
+      if (!ipcp_lat_is_const (old_lat))
        return false;
-      if (ipcp_lats_are_equal (old, new))
+      if (ipcp_lats_are_equal (old_lat, new_lat))
        return false;
     }
   return true;
@@ -290,70 +368,192 @@ ipcp_print_all_lattices (FILE * f)
   struct cgraph_node *node;
   int i, count;
 
-  fprintf (f, "\nLATTICE PRINT\n");
+  fprintf (f, "\nLattice:\n");
   for (node = cgraph_nodes; node; node = node->next)
     {
-      struct ipa_node_params *info = IPA_NODE_REF (node);
-      fprintf (f, "Printing lattices %s:\n", cgraph_node_name (node));
+      struct ipa_node_params *info;
+
+      if (!node->analyzed)
+       continue;
+      info = IPA_NODE_REF (node);
+      fprintf (f, "  Node: %s:\n", cgraph_node_name (node));
       count = ipa_get_param_count (info);
       for (i = 0; i < count; i++)
        {
-         struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-         if (lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
+         struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+
+         fprintf (f, "    param [%d]: ", i);
+         if (lat->type == IPA_CONST_VALUE)
            {
-             fprintf (f, " param [%d]: ", i);
              fprintf (f, "type is CONST ");
              print_generic_expr (f, lat->constant, 0);
              fprintf (f, "\n");
            }
          else if (lat->type == IPA_TOP)
-           fprintf (f, "param [%d]: type is TOP  \n", i);
+           fprintf (f, "type is TOP\n");
          else
-           fprintf (f, "param [%d]: type is BOTTOM  \n", i);
+           fprintf (f, "type is BOTTOM\n");
        }
     }
 }
 
-/* Initialize ipcp_lattices array.  The lattices corresponding to supported
-   types (integers, real types and Fortran constants defined as const_decls)
-   are initialized to IPA_TOP, the rest of them to IPA_BOTTOM.  */
-static void
-ipcp_initialize_node_lattices (struct cgraph_node *node)
+/* Return true if ipcp algorithms would allow cloning NODE.  */
+
+static bool
+ipcp_versionable_function_p (struct cgraph_node *node)
 {
-  int i;
-  struct ipa_node_params *info = IPA_NODE_REF (node);
+  tree decl = node->decl;
+  basic_block bb;
 
-  info->ipcp_lattices = XCNEWVEC (struct ipcp_lattice,
-                                 ipa_get_param_count (info));
-  for (i = 0; i < ipa_get_param_count (info) ; i++)
+  /* There are a number of generic reasons functions cannot be versioned.  */
+  if (!tree_versionable_function_p (decl))
+    return false;
+
+  /* Removing arguments doesn't work if the function takes varargs.  */
+  if (DECL_STRUCT_FUNCTION (decl)->stdarg)
+    return false;
+
+  /* Removing arguments doesn't work if we use __builtin_apply_args.  */
+  FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (decl))
     {
-      tree parm_tree = ipa_get_ith_param (info, i);
-      struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
+      gimple_stmt_iterator gsi;
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         const_gimple stmt = gsi_stmt (gsi);
+         tree t;
 
-      if (INTEGRAL_TYPE_P (TREE_TYPE (parm_tree))
-         || SCALAR_FLOAT_TYPE_P (TREE_TYPE (parm_tree))
-         || POINTER_TYPE_P (TREE_TYPE (parm_tree)))
-       lat->type = IPA_TOP;
-      else
-       lat->type = IPA_BOTTOM;
+         if (!is_gimple_call (stmt))
+           continue;
+         t = gimple_call_fndecl (stmt);
+         if (t == NULL_TREE)
+           continue;
+         if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
+             && DECL_FUNCTION_CODE (t) == BUILT_IN_APPLY_ARGS)
+           return false;
+       }
     }
+
+  return true;
 }
 
-/* Create a new assignment statement and make it the first statement in the
-   function.  PARM1 is the lhs of the assignment and VAL is the rhs. */
-static void
-constant_val_insert (tree parm1, tree val)
+/* Return true if this NODE is viable candidate for cloning.  */
+static bool
+ipcp_cloning_candidate_p (struct cgraph_node *node)
 {
-  tree init_stmt = NULL;
-  edge e_step;
+  int n_calls = 0;
+  int n_hot_calls = 0;
+  gcov_type direct_call_sum = 0;
+  struct cgraph_edge *e;
+
+  /* We never clone functions that are not visible from outside.
+     FIXME: in future we should clone such functions when they are called with
+     different constants, but current ipcp implementation is not good on this.
+     */
+  if (cgraph_only_called_directly_p (node) || !node->analyzed)
+    return false;
+
+  if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
+    {
+      if (dump_file)
+        fprintf (dump_file, "Not considering %s for cloning; body is overwrittable.\n",
+                cgraph_node_name (node));
+      return false;
+    }
+  if (!ipcp_versionable_function_p (node))
+    {
+      if (dump_file)
+        fprintf (dump_file, "Not considering %s for cloning; body is not versionable.\n",
+                cgraph_node_name (node));
+      return false;
+    }
+  for (e = node->callers; e; e = e->next_caller)
+    {
+      direct_call_sum += e->count;
+      n_calls ++;
+      if (cgraph_maybe_hot_edge_p (e))
+       n_hot_calls ++;
+    }
+  
+  if (!n_calls)
+    {
+      if (dump_file)
+        fprintf (dump_file, "Not considering %s for cloning; no direct calls.\n",
+                cgraph_node_name (node));
+      return false;
+    }
+  if (node->local.inline_summary.self_size < n_calls)
+    {
+      if (dump_file)
+        fprintf (dump_file, "Considering %s for cloning; code would shrink.\n",
+                cgraph_node_name (node));
+      return true;
+    }  
+
+  if (!flag_ipa_cp_clone)
+    {
+      if (dump_file)
+        fprintf (dump_file, "Not considering %s for cloning; -fipa-cp-clone disabled.\n",
+                cgraph_node_name (node));
+      return false;
+    }
 
-  init_stmt = build_gimple_modify_stmt (parm1, val);
+  if (!optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->decl)))
+    {
+      if (dump_file)
+        fprintf (dump_file, "Not considering %s for cloning; optimizing it for size.\n",
+                cgraph_node_name (node));
+      return false;
+    }
 
-  if (init_stmt)
+  /* When profile is available and function is hot, propagate into it even if
+     calls seems cold; constant propagation can improve function's speed
+     significandly.  */
+  if (max_count)
     {
-      e_step = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun));
-      bsi_insert_on_edge_immediate (e_step, init_stmt);
+      if (direct_call_sum > node->count * 90 / 100)
+       {
+         if (dump_file)
+           fprintf (dump_file, "Considering %s for cloning; usually called directly.\n",
+                    cgraph_node_name (node));
+         return true;
+        }
     }
+  if (!n_hot_calls)
+    {
+      if (dump_file)
+       fprintf (dump_file, "Not considering %s for cloning; no hot calls.\n",
+                cgraph_node_name (node));
+      return false;
+    }
+  if (dump_file)
+    fprintf (dump_file, "Considering %s for cloning.\n",
+            cgraph_node_name (node));
+  return true;
+}
+
+/* Initialize ipcp_lattices array.  The lattices corresponding to supported
+   types (integers, real types and Fortran constants defined as const_decls)
+   are initialized to IPA_TOP, the rest of them to IPA_BOTTOM.  */
+static void
+ipcp_initialize_node_lattices (struct cgraph_node *node)
+{
+  int i;
+  struct ipa_node_params *info = IPA_NODE_REF (node);
+  enum ipa_lattice_type type;
+
+  if (ipa_is_called_with_var_arguments (info))
+    type = IPA_BOTTOM;
+  else if (cgraph_only_called_directly_p (node))
+    type = IPA_TOP;
+  /* When cloning is allowed, we can assume that externally visible functions
+     are not called.  We will compensate this by cloning later.  */
+  else if (ipcp_cloning_candidate_p (node))
+    type = IPA_TOP, n_cloning_candidates ++;
+  else
+    type = IPA_BOTTOM;
+
+  for (i = 0; i < ipa_get_param_count (info) ; i++)
+    ipcp_get_lattice (info, i)->type = type;
 }
 
 /* build INTEGER_CST tree with type TREE_TYPE and value according to LAT.
@@ -361,26 +561,19 @@ constant_val_insert (tree parm1, tree val)
 static tree
 build_const_val (struct ipcp_lattice *lat, tree tree_type)
 {
-  tree const_val = NULL;
+  tree val;
 
   gcc_assert (ipcp_lat_is_const (lat));
-  const_val = fold_convert (tree_type, lat->constant);
-  return const_val;
-}
+  val = lat->constant;
 
-/* Build the tree representing the constant and call constant_val_insert().  */
-static void
-ipcp_propagate_one_const (struct cgraph_node *node, int param,
-                         struct ipcp_lattice *lat)
-{
-  tree const_val;
-  tree parm_tree;
-
-  if (dump_file)
-    fprintf (dump_file, "propagating const to %s\n", cgraph_node_name (node));
-  parm_tree = ipa_get_ith_param (IPA_NODE_REF (node), param);
-  const_val = build_const_val (lat, TREE_TYPE (parm_tree));
-  constant_val_insert (parm_tree, const_val);
+  if (!useless_type_conversion_p (tree_type, TREE_TYPE (val)))
+    {
+      if (fold_convertible_p (tree_type, val))
+       return fold_build1 (NOP_EXPR, tree_type, val);
+      else
+       return fold_build1 (VIEW_CONVERT_EXPR, tree_type, val);
+    }
+  return val;
 }
 
 /* Compute the proper scale for NODE.  It is the ratio between the number of
@@ -412,18 +605,19 @@ ipcp_init_stage (void)
   struct cgraph_edge *cs;
 
   for (node = cgraph_nodes; node; node = node->next)
-    {
-      ipa_count_formal_params (node);
-      ipa_create_param_decls_array (node);
-      ipcp_initialize_node_lattices (node);
-      ipa_detect_param_modifications (node);
-      ipcp_compute_node_scale (node);
-    }
+    if (node->analyzed)
+      ipcp_analyze_node (node);
   for (node = cgraph_nodes; node; node = node->next)
     {
+      if (!node->analyzed)
+       continue;
       /* building jump functions  */
       for (cs = node->callees; cs; cs = cs->next_callee)
        {
+         /* We do not need to bother analyzing calls to unknown
+            functions unless they may become known during lto/whopr.  */
+         if (!cs->callee->analyzed && !flag_lto && !flag_whopr)
+           continue;
          ipa_count_arguments (cs);
          if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
              != ipa_get_param_count (IPA_NODE_REF (cs->callee)))
@@ -431,6 +625,8 @@ ipcp_init_stage (void)
              /* Handle cases of functions with 
                 a variable number of parameters.  */
              ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
+             if (flag_indirect_inlining)
+               ipa_compute_jump_functions (cs);
            }
          else
            ipa_compute_jump_functions (cs);
@@ -455,10 +651,17 @@ ipcp_change_tops_to_bottom (void)
       count = ipa_get_param_count (info);
       for (i = 0; i < count; i++)
        {
-         struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
+         struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
          if (lat->type == IPA_TOP)
            {
              prop_again = true;
+             if (dump_file)
+               {
+                 fprintf (dump_file, "Forcing param ");
+                 print_generic_expr (dump_file, ipa_get_param (info, i), 0);
+                 fprintf (dump_file, " of node %s to bottom.\n",
+                          cgraph_node_name (node));
+               }
              lat->type = IPA_BOTTOM;
            }
        }
@@ -480,6 +683,9 @@ ipcp_propagate_stage (void)
   struct ipa_func_list *wl;
   int count;
 
+  ipa_check_create_node_params ();
+  ipa_check_create_edge_args ();
+
   /* Initialize worklist to contain all functions.  */
   wl = ipa_init_func_list ();
   while (wl)
@@ -492,7 +698,9 @@ ipcp_propagate_stage (void)
          struct ipa_node_params *callee_info = IPA_NODE_REF (cs->callee);
          struct ipa_edge_args *args = IPA_EDGE_REF (cs);
 
-         if (ipa_is_called_with_var_arguments (callee_info))
+         if (ipa_is_called_with_var_arguments (callee_info)
+             || !cs->callee->analyzed
+             || ipa_is_called_with_var_arguments (callee_info))
            continue;
 
          count = ipa_get_cs_argument_count (args);
@@ -500,7 +708,7 @@ ipcp_propagate_stage (void)
            {
              jump_func = ipa_get_ith_jump_func (args, i);
              ipcp_lattice_from_jfunc (info, &inc_lat, jump_func);
-             dest_lat = ipcp_get_ith_lattice (callee_info, i);
+             dest_lat = ipcp_get_lattice (callee_info, i);
              ipa_lattice_meet (&new_lat, &inc_lat, dest_lat);
              if (ipcp_lattice_changed (&new_lat, dest_lat))
                {
@@ -518,70 +726,51 @@ ipcp_propagate_stage (void)
 static void
 ipcp_iterate_stage (void)
 {
+  struct cgraph_node *node;
+  n_cloning_candidates = 0;
+
+  if (dump_file)
+    fprintf (dump_file, "\nIPA iterate stage:\n\n");
+
+  if (in_lto_p)
+    ipa_update_after_lto_read ();
+
+  for (node = cgraph_nodes; node; node = node->next)
+    {
+      ipcp_initialize_node_lattices (node);
+      ipcp_compute_node_scale (node);
+    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      ipcp_print_all_lattices (dump_file);
+      ipcp_function_scale_print (dump_file);
+    }
+
   ipcp_propagate_stage ();
   if (ipcp_change_tops_to_bottom ())
     /* Some lattices have changed from IPA_TOP to IPA_BOTTOM.
        This change should be propagated.  */
-    ipcp_propagate_stage ();
+    {
+      gcc_assert (n_cloning_candidates);
+      ipcp_propagate_stage ();
+    }
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nIPA lattices after propagation:\n");
+      ipcp_print_all_lattices (dump_file);
+      if (dump_flags & TDF_DETAILS)
+        ipcp_print_profile_data (dump_file);
+    }
 }
 
 /* Check conditions to forbid constant insertion to function described by
    NODE.  */
 static inline bool
-ipcp_node_not_modifiable_p (struct cgraph_node *node)
-{
-  /* ??? Handle pending sizes case.  */
-  if (DECL_UNINLINABLE (node->decl))
-    return true;
-  return false;
-}
-
-/* Print ipa_jump_func data structures to F.  */
-static void
-ipcp_print_all_jump_functions (FILE * f)
+ipcp_node_modifiable_p (struct cgraph_node *node)
 {
-  struct cgraph_node *node;
-  int i, count;
-  struct cgraph_edge *cs;
-  struct ipa_jump_func *jump_func;
-  enum jump_func_type type;
-  tree info_type;
-
-  fprintf (f, "\nCALLSITE PARAM PRINT\n");
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      for (cs = node->callees; cs; cs = cs->next_callee)
-       {
-         fprintf (f, "callsite  %s ", cgraph_node_name (node));
-         fprintf (f, "-> %s :: \n", cgraph_node_name (cs->callee));
-
-         if (ipa_is_called_with_var_arguments (IPA_NODE_REF (cs->callee)))
-           continue;
-
-         count = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
-         for (i = 0; i < count; i++)
-           {
-             jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
-             type = jump_func->type;
-
-             fprintf (f, " param %d: ", i);
-             if (type == IPA_UNKNOWN)
-               fprintf (f, "UNKNOWN\n");
-             else if (type == IPA_CONST || type == IPA_CONST_REF)
-               {
-                 info_type = jump_func->value.constant;
-                 fprintf (f, "CONST : ");
-                 print_generic_expr (f, info_type, 0);
-                 fprintf (f, "\n");
-               }
-             else if (type == IPA_PASS_THROUGH)
-               {
-                 fprintf (f, "PASS THROUGH : ");
-                 fprintf (f, "%d\n", jump_func->value.formal_id);
-               }
-           }
-       }
-    }
+  /* Once we will be able to do in-place replacement, we can be more
+     lax here.  */
+  return ipcp_versionable_function_p (node);
 }
 
 /* Print count scale data structures.  */
@@ -592,6 +781,8 @@ ipcp_function_scale_print (FILE * f)
 
   for (node = cgraph_nodes; node; node = node->next)
     {
+      if (!node->analyzed)
+       continue;
       fprintf (f, "printing scale for %s: ", cgraph_node_name (node));
       fprintf (f, "value is  " HOST_WIDE_INT_PRINT_DEC
               "  \n", (HOST_WIDE_INT) ipcp_get_node_scale (node));
@@ -631,109 +822,6 @@ ipcp_print_call_profile_counts (FILE * f)
     }
 }
 
-/* Print all counts and probabilities of cfg edges of all functions.  */
-static void
-ipcp_print_edge_profiles (FILE * f)
-{
-  struct cgraph_node *node;
-  basic_block bb;
-  edge_iterator ei;
-  edge e;
-
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      fprintf (f, "function %s: \n", cgraph_node_name (node));
-      if (DECL_SAVED_TREE (node->decl))
-       {
-         bb =
-           ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
-         fprintf (f, "ENTRY: ");
-         fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                  " %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
-
-         if (bb->succs)
-           FOR_EACH_EDGE (e, ei, bb->succs)
-           {
-             if (e->dest ==
-                 EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
-                                              (node->decl)))
-               fprintf (f, "edge ENTRY -> EXIT,  Count");
-             else
-               fprintf (f, "edge ENTRY -> %d,  Count", e->dest->index);
-             fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                      " Prob %d\n", (HOST_WIDE_INT) e->count,
-                      e->probability);
-           }
-         FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-         {
-           fprintf (f, "bb[%d]: ", bb->index);
-           fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                    " %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
-           FOR_EACH_EDGE (e, ei, bb->succs)
-           {
-             if (e->dest ==
-                 EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
-                                              (node->decl)))
-               fprintf (f, "edge %d -> EXIT,  Count", e->src->index);
-             else
-               fprintf (f, "edge %d -> %d,  Count", e->src->index,
-                        e->dest->index);
-             fprintf (f, " " HOST_WIDE_INT_PRINT_DEC " Prob %d\n",
-                      (HOST_WIDE_INT) e->count, e->probability);
-           }
-         }
-       }
-    }
-}
-
-/* Print counts and frequencies for all basic blocks of all functions.  */
-static void
-ipcp_print_bb_profiles (FILE * f)
-{
-  basic_block bb;
-  struct cgraph_node *node;
-
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      fprintf (f, "function %s: \n", cgraph_node_name (node));
-      if (node->analyzed)
-       {
-         bb =
-           ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
-         fprintf (f, "ENTRY: Count");
-         fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                  " Frequency  %d\n", (HOST_WIDE_INT) bb->count,
-                  bb->frequency);
-
-         FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-         {
-           fprintf (f, "bb[%d]: Count", bb->index);
-           fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                    " Frequency %d\n", (HOST_WIDE_INT) bb->count,
-                    bb->frequency);
-         }
-         bb =
-           EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
-         fprintf (f, "EXIT: Count");
-         fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                  " Frequency %d\n", (HOST_WIDE_INT) bb->count,
-                  bb->frequency);
-
-       }
-    }
-}
-
-/* Print all IPCP data structures to F.  */
-static void
-ipcp_print_all_structures (FILE * f)
-{
-  ipcp_print_all_lattices (f);
-  ipcp_function_scale_print (f);
-  ipa_print_all_tree_maps (f);
-  ipa_print_all_params_modified (f);
-  ipcp_print_all_jump_functions (f);
-}
-
 /* Print profile info for all functions.  */
 static void
 ipcp_print_profile_data (FILE * f)
@@ -742,10 +830,6 @@ ipcp_print_profile_data (FILE * f)
   ipcp_print_func_profile_counts (f);
   fprintf (f, "\nCS COUNTS stage:\n");
   ipcp_print_call_profile_counts (f);
-  fprintf (f, "\nBB COUNTS and FREQUENCIES :\n");
-  ipcp_print_bb_profiles (f);
-  fprintf (f, "\nCFG EDGES COUNTS and PROBABILITIES :\n");
-  ipcp_print_edge_profiles (f);
 }
 
 /* Build and initialize ipa_replace_map struct according to LAT. This struct is
@@ -753,34 +837,25 @@ ipcp_print_profile_data (FILE * f)
    PARM_TREE is the formal parameter found to be constant.  LAT represents the
    constant.  */
 static struct ipa_replace_map *
-ipcp_create_replace_map (struct function *func, tree parm_tree,
-                        struct ipcp_lattice *lat)
+ipcp_create_replace_map (tree parm_tree, struct ipcp_lattice *lat)
 {
   struct ipa_replace_map *replace_map;
   tree const_val;
 
-  replace_map = XCNEW (struct ipa_replace_map);
-  gcc_assert (ipcp_lat_is_const (lat));
-  if (lat->type != IPA_CONST_VALUE_REF
-      && is_gimple_reg (parm_tree) && gimple_default_def (func, parm_tree)
-       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_default_def (func,
-                                                                parm_tree)))
-    {
-      if (dump_file)
-       fprintf (dump_file, "replacing param with const\n");
-      const_val = build_const_val (lat, TREE_TYPE (parm_tree));
-      replace_map->old_tree =gimple_default_def (func, parm_tree);
-      replace_map->new_tree = const_val;
-      replace_map->replace_p = true;
-      replace_map->ref_p = false;
-    }
-  else
+  replace_map = GGC_NEW (struct ipa_replace_map);
+  const_val = build_const_val (lat, TREE_TYPE (parm_tree));
+  if (dump_file)
     {
-      replace_map->old_tree = NULL;
-      replace_map->new_tree = NULL;
-      replace_map->replace_p = false;
-      replace_map->ref_p = false;
+      fprintf (dump_file, "  replacing param ");
+      print_generic_expr (dump_file, parm_tree, 0);
+      fprintf (dump_file, " with const ");
+      print_generic_expr (dump_file, const_val, 0);
+      fprintf (dump_file, "\n");
     }
+  replace_map->old_tree = parm_tree;
+  replace_map->new_tree = const_val;
+  replace_map->replace_p = true;
+  replace_map->ref_p = false;
 
   return replace_map;
 }
@@ -793,16 +868,25 @@ ipcp_need_redirect_p (struct cgraph_edge *cs)
   struct ipa_node_params *orig_callee_info;
   int i, count;
   struct ipa_jump_func *jump_func;
+  struct cgraph_node *node = cs->callee, *orig;
+
+  if (!n_cloning_candidates)
+    return false;
 
-  orig_callee_info = IPA_NODE_REF (ipcp_get_orig_node (cs->callee));
+  if ((orig = ipcp_get_orig_node (node)) != NULL)
+    node = orig;
+  if (ipcp_get_orig_node (cs->caller))
+    return false;
+
+  orig_callee_info = IPA_NODE_REF (node);
   count = ipa_get_param_count (orig_callee_info);
   for (i = 0; i < count; i++)
     {
-      struct ipcp_lattice *lat = ipcp_get_ith_lattice (orig_callee_info, i);
+      struct ipcp_lattice *lat = ipcp_get_lattice (orig_callee_info, i);
       if (ipcp_lat_is_const (lat))
        {
          jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
-         if (!ipcp_lat_is_const (lat))
+         if (jump_func->type != IPA_JF_CONST)
            return true;
        }
     }
@@ -814,51 +898,41 @@ ipcp_need_redirect_p (struct cgraph_edge *cs)
 static void
 ipcp_update_callgraph (void)
 {
-  struct cgraph_node *node, *orig_callee;
-  struct cgraph_edge *cs;
+  struct cgraph_node *node;
 
   for (node = cgraph_nodes; node; node = node->next)
-    {
-      /* want to fix only original nodes  */
-      if (ipcp_node_is_clone (node))
-       continue;
-      for (cs = node->callees; cs; cs = cs->next_callee)
-       if (ipcp_node_is_clone (cs->callee))
+    if (node->analyzed && ipcp_node_is_clone (node))
+      {
+       bitmap args_to_skip = BITMAP_ALLOC (NULL);
+       struct cgraph_node *orig_node = ipcp_get_orig_node (node);
+        struct ipa_node_params *info = IPA_NODE_REF (orig_node);
+        int i, count = ipa_get_param_count (info);
+        struct cgraph_edge *cs, *next;
+
+       for (i = 0; i < count; i++)
          {
-           /* Callee is a cloned node  */
-           orig_callee = ipcp_get_orig_node (cs->callee);
-           if (ipcp_need_redirect_p (cs))
+           struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+           tree parm_tree = ipa_get_param (info, i);
+
+           /* We can proactively remove obviously unused arguments.  */
+           if (is_gimple_reg (parm_tree)
+               && !gimple_default_def (DECL_STRUCT_FUNCTION (orig_node->decl),
+                                       parm_tree))
              {
-               cgraph_redirect_edge_callee (cs, orig_callee);
-               TREE_OPERAND (CALL_EXPR_FN (get_call_expr_in (cs->call_stmt)),
-                             0) =
-                 orig_callee->decl;
+               bitmap_set_bit (args_to_skip, i);
+               continue;
              }
-         }
-    }
-}
-
-/* Update all cfg basic blocks in NODE according to SCALE.  */
-static void
-ipcp_update_bb_counts (struct cgraph_node *node, gcov_type scale)
-{
-  basic_block bb;
 
-  FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-    bb->count = bb->count * scale / REG_BR_PROB_BASE;
-}
-
-/* Update all cfg edges in NODE according to SCALE.  */
-static void
-ipcp_update_edges_counts (struct cgraph_node *node, gcov_type scale)
-{
-  basic_block bb;
-  edge_iterator ei;
-  edge e;
-
-  FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-    FOR_EACH_EDGE (e, ei, bb->succs)
-    e->count = e->count * scale / REG_BR_PROB_BASE;
+           if (lat->type == IPA_CONST_VALUE)
+             bitmap_set_bit (args_to_skip, i);
+         }
+       for (cs = node->callers; cs; cs = next)
+         {
+           next = cs->next_caller;
+           if (!ipcp_node_is_clone (cs->caller) && ipcp_need_redirect_p (cs))
+             cgraph_redirect_edge_callee (cs, orig_node);
+         }
+      }
 }
 
 /* Update profiling info for versioned functions and the functions they were
@@ -884,59 +958,237 @@ ipcp_update_profiling (void)
            cs->count = cs->count * scale / REG_BR_PROB_BASE;
          for (cs = orig_node->callees; cs; cs = cs->next_callee)
            cs->count = cs->count * scale_complement / REG_BR_PROB_BASE;
-         ipcp_update_bb_counts (node, scale);
-         ipcp_update_bb_counts (orig_node, scale_complement);
-         ipcp_update_edges_counts (node, scale);
-         ipcp_update_edges_counts (orig_node, scale_complement);
        }
     }
 }
 
+/* If NODE was cloned, how much would program grow? */
+static long
+ipcp_estimate_growth (struct cgraph_node *node)
+{
+  struct cgraph_edge *cs;
+  int redirectable_node_callers = 0;
+  int removable_args = 0;
+  bool need_original = !cgraph_only_called_directly_p (node);
+  struct ipa_node_params *info;
+  int i, count;
+  int growth;
+
+  for (cs = node->callers; cs != NULL; cs = cs->next_caller)
+    if (cs->caller == node || !ipcp_need_redirect_p (cs))
+      redirectable_node_callers++;
+    else
+      need_original = true;
+
+  /* If we will be able to fully replace orignal node, we never increase
+     program size.  */
+  if (!need_original)
+    return 0;
+
+  info = IPA_NODE_REF (node);
+  count = ipa_get_param_count (info);
+  for (i = 0; i < count; i++)
+    {
+      struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+      tree parm_tree = ipa_get_param (info, i);
+
+      /* We can proactively remove obviously unused arguments.  */
+      if (is_gimple_reg (parm_tree)
+         && !gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
+                                 parm_tree))
+       removable_args++;
+
+      if (lat->type == IPA_CONST_VALUE)
+       removable_args++;
+    }
+
+  /* We make just very simple estimate of savings for removal of operand from
+     call site.  Precise cost is dificult to get, as our size metric counts
+     constants and moves as free.  Generally we are looking for cases that
+     small function is called very many times.  */
+  growth = node->local.inline_summary.self_size
+          - removable_args * redirectable_node_callers;
+  if (growth < 0)
+    return 0;
+  return growth;
+}
+
+
+/* Estimate cost of cloning NODE.  */
+static long
+ipcp_estimate_cloning_cost (struct cgraph_node *node)
+{
+  int freq_sum = 1;
+  gcov_type count_sum = 1;
+  struct cgraph_edge *e;
+  int cost;
+
+  cost = ipcp_estimate_growth (node) * 1000;
+  if (!cost)
+    {
+      if (dump_file)
+        fprintf (dump_file, "Versioning of %s will save code size\n",
+                cgraph_node_name (node));
+      return 0;
+    }
+
+  for (e = node->callers; e; e = e->next_caller)
+    if (!bitmap_bit_p (dead_nodes, e->caller->uid)
+        && !ipcp_need_redirect_p (e))
+      {
+       count_sum += e->count;
+       freq_sum += e->frequency + 1;
+      }
+
+  if (max_count)
+    cost /= count_sum * 1000 / max_count + 1;
+  else
+    cost /= freq_sum * 1000 / REG_BR_PROB_BASE + 1;
+  if (dump_file)
+    fprintf (dump_file, "Cost of versioning %s is %i, (size: %i, freq: %i)\n",
+             cgraph_node_name (node), cost, node->local.inline_summary.self_size,
+            freq_sum);
+  return cost + 1;
+}
+
+/* Return number of live constant parameters.  */
+static int
+ipcp_const_param_count (struct cgraph_node *node)
+{
+  int const_param = 0;
+  struct ipa_node_params *info = IPA_NODE_REF (node);
+  int count = ipa_get_param_count (info);
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+      tree parm_tree = ipa_get_param (info, i);
+      if (ipcp_lat_is_insertable (lat)
+         /* Do not count obviously unused arguments.  */
+         && (!is_gimple_reg (parm_tree)
+             || gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
+                                    parm_tree)))
+       const_param++;
+    }
+  return const_param;
+}
+
 /* Propagate the constant parameters found by ipcp_iterate_stage()
    to the function's code.  */
 static void
 ipcp_insert_stage (void)
 {
   struct cgraph_node *node, *node1 = NULL;
-  int i, const_param;
+  int i;
   VEC (cgraph_edge_p, heap) * redirect_callers;
-  varray_type replace_trees;
-  struct cgraph_edge *cs;
+  VEC (ipa_replace_map_p,gc)* replace_trees;
   int node_callers, count;
   tree parm_tree;
   struct ipa_replace_map *replace_param;
+  fibheap_t heap;
+  long overall_size = 0, new_size = 0;
+  long max_new_size;
+
+  ipa_check_create_node_params ();
+  ipa_check_create_edge_args ();
+  if (dump_file)
+    fprintf (dump_file, "\nIPA insert stage:\n\n");
 
+  dead_nodes = BITMAP_ALLOC (NULL);
+
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->analyzed)
+      {
+       if (node->count > max_count)
+         max_count = node->count;
+       overall_size += node->local.inline_summary.self_size;
+      }
+
+  max_new_size = overall_size;
+  if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
+    max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
+  max_new_size = max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1;
+
+  /* First collect all functions we proved to have constant arguments to heap.  */
+  heap = fibheap_new ();
   for (node = cgraph_nodes; node; node = node->next)
     {
-      struct ipa_node_params *info = IPA_NODE_REF (node);
-      /* Propagation of the constant is forbidden in 
-         certain conditions.  */
-      if (!node->analyzed || ipcp_node_not_modifiable_p (node)
-         || ipa_is_called_with_var_arguments (info))
+      struct ipa_node_params *info;
+      /* Propagation of the constant is forbidden in certain conditions.  */
+      if (!node->analyzed || !ipcp_node_modifiable_p (node))
+         continue;
+      info = IPA_NODE_REF (node);
+      if (ipa_is_called_with_var_arguments (info))
        continue;
-      const_param = 0;
-      count = ipa_get_param_count (info);
-      for (i = 0; i < count; i++)
+      if (ipcp_const_param_count (node))
+       node->aux = fibheap_insert (heap, ipcp_estimate_cloning_cost (node), node);
+     }
+
+  /* Now clone in priority order until code size growth limits are met or
+     heap is emptied.  */
+  while (!fibheap_empty (heap))
+    {
+      struct ipa_node_params *info;
+      int growth = 0;
+      bitmap args_to_skip;
+      struct cgraph_edge *cs;
+
+      node = (struct cgraph_node *)fibheap_extract_min (heap);
+      node->aux = NULL;
+      if (dump_file)
+       fprintf (dump_file, "considering function %s\n",
+                cgraph_node_name (node));
+
+      growth = ipcp_estimate_growth (node);
+
+      if (new_size + growth > max_new_size)
+       break;
+      if (growth
+         && optimize_function_for_size_p (DECL_STRUCT_FUNCTION (node->decl)))
        {
-         struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-         if (ipcp_lat_is_const (lat))
-           const_param++;
+         if (dump_file)
+           fprintf (dump_file, "Not versioning, cold code would grow");
+         continue;
        }
-      if (const_param == 0)
-       continue;
-      VARRAY_GENERIC_PTR_INIT (replace_trees, const_param, "replace_trees");
+
+      new_size += growth;
+
+      /* Look if original function becomes dead after clonning.  */
+      for (cs = node->callers; cs != NULL; cs = cs->next_caller)
+       if (cs->caller == node || ipcp_need_redirect_p (cs))
+         break;
+      if (!cs && cgraph_only_called_directly_p (node))
+       bitmap_set_bit (dead_nodes, node->uid);
+
+      info = IPA_NODE_REF (node);
+      count = ipa_get_param_count (info);
+
+      replace_trees = VEC_alloc (ipa_replace_map_p, gc, 1);
+      args_to_skip = BITMAP_GGC_ALLOC ();
       for (i = 0; i < count; i++)
        {
-         struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-         if (ipcp_lat_is_const (lat))
+         struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+         parm_tree = ipa_get_param (info, i);
+
+         /* We can proactively remove obviously unused arguments.  */
+         if (is_gimple_reg (parm_tree)
+             && !gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
+                                     parm_tree))
+           {
+             bitmap_set_bit (args_to_skip, i);
+             continue;
+           }
+
+         if (lat->type == IPA_CONST_VALUE)
            {
-             parm_tree = ipa_get_ith_param (info, i);
              replace_param =
-               ipcp_create_replace_map (DECL_STRUCT_FUNCTION (node->decl),
-                                        parm_tree, lat);
-             VARRAY_PUSH_GENERIC_PTR (replace_trees, replace_param);
+               ipcp_create_replace_map (parm_tree, lat);
+             VEC_safe_push (ipa_replace_map_p, gc, replace_trees, replace_param);
+             bitmap_set_bit (args_to_skip, i);
            }
        }
+
       /* Compute how many callers node has.  */
       node_callers = 0;
       for (cs = node->callers; cs != NULL; cs = cs->next_caller)
@@ -944,50 +1196,48 @@ ipcp_insert_stage (void)
       redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
       for (cs = node->callers; cs != NULL; cs = cs->next_caller)
        VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
+
       /* Redirecting all the callers of the node to the
          new versioned node.  */
       node1 =
-       cgraph_function_versioning (node, redirect_callers, replace_trees);
+       cgraph_create_virtual_clone (node, redirect_callers, replace_trees,
+                                    args_to_skip);
+      args_to_skip = NULL;
       VEC_free (cgraph_edge_p, heap, redirect_callers);
-      VARRAY_CLEAR (replace_trees);
+      replace_trees = NULL;
+
       if (node1 == NULL)
        continue;
       if (dump_file)
-       fprintf (dump_file, "versioned function %s\n",
-                cgraph_node_name (node));
+       fprintf (dump_file, "versioned function %s with growth %i, overall %i\n",
+                cgraph_node_name (node), (int)growth, (int)new_size);
       ipcp_init_cloned_node (node, node1);
-      if (const_param > 0)
-       {
-         push_cfun (DECL_STRUCT_FUNCTION (node1->decl));
-         tree_register_cfg_hooks ();
-         current_function_decl = node1->decl;
 
-         for (i = 0; i < count; i++)
-           {
-             struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-             if (ipcp_lat_is_const (lat))
-               {
-                 parm_tree = ipa_get_ith_param (info, i);
-                 if (lat->type != IPA_CONST_VALUE_REF
-                     && !is_gimple_reg (parm_tree))
-                   ipcp_propagate_one_const (node1, i, lat);
-               }
-           }
-         if (gimple_in_ssa_p (cfun))
-           {
-             update_ssa (TODO_update_ssa);
-#ifdef   ENABLE_CHECKING
-             verify_ssa (true);
-#endif
-           }
-         free_dominance_info (CDI_DOMINATORS);
-         free_dominance_info (CDI_POST_DOMINATORS);
-         pop_cfun ();
-         current_function_decl = NULL;
-       }
+      /* TODO: We can use indirect inlning info to produce new calls.  */
+
       if (dump_file)
        dump_function_to_file (node1->decl, dump_file, dump_flags);
+
+      for (cs = node->callees; cs; cs = cs->next_callee)
+        if (cs->callee->aux)
+         {
+           fibheap_delete_node (heap, (fibnode_t) cs->callee->aux);
+           cs->callee->aux = fibheap_insert (heap,
+                                             ipcp_estimate_cloning_cost (cs->callee),
+                                             cs->callee);
+         }
     }
+
+  while (!fibheap_empty (heap))
+    {
+      if (dump_file)
+       fprintf (dump_file, "skipping function %s\n",
+                cgraph_node_name (node));
+      node = (struct cgraph_node *) fibheap_extract_min (heap);
+      node->aux = NULL;
+    }
+  fibheap_delete (heap);
+  BITMAP_FREE (dead_nodes);
   ipcp_update_callgraph ();
   ipcp_update_profiling ();
 }
@@ -996,43 +1246,58 @@ ipcp_insert_stage (void)
 static unsigned int
 ipcp_driver (void)
 {
-  if (dump_file)
-    fprintf (dump_file, "\nIPA constant propagation start:\n");
-  ipa_create_all_node_params ();
-  ipa_create_all_edge_args ();
-  /* 1. Call the init stage to initialize 
-     the ipa_node_params and ipa_edge_args structures.  */
-  ipcp_init_stage ();
+  cgraph_remove_unreachable_nodes (true,dump_file);
   if (dump_file)
     {
       fprintf (dump_file, "\nIPA structures before propagation:\n");
-      ipcp_print_all_structures (dump_file);
+      if (dump_flags & TDF_DETAILS)
+        ipa_print_all_params (dump_file);
+      ipa_print_all_jump_functions (dump_file);
     }
   /* 2. Do the interprocedural propagation.  */
   ipcp_iterate_stage ();
-  if (dump_file)
-    {
-      fprintf (dump_file, "\nIPA structures after propagation:\n");
-      ipcp_print_all_structures (dump_file);
-      fprintf (dump_file, "\nProfiling info before insert stage:\n");
-      ipcp_print_profile_data (dump_file);
-    }
   /* 3. Insert the constants found to the functions.  */
   ipcp_insert_stage ();
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "\nProfiling info after insert stage:\n");
       ipcp_print_profile_data (dump_file);
     }
   /* Free all IPCP structures.  */
-  ipa_free_all_node_params ();
-  ipa_free_all_edge_args ();
+  free_all_ipa_structures_after_ipa_cp ();
   if (dump_file)
     fprintf (dump_file, "\nIPA constant propagation end\n");
-  cgraph_remove_unreachable_nodes (true, NULL);
   return 0;
 }
 
+/* Note function body size.  */
+static void
+ipcp_generate_summary (void)
+{
+  if (dump_file)
+    fprintf (dump_file, "\nIPA constant propagation start:\n");
+  ipa_check_create_node_params ();
+  ipa_check_create_edge_args ();
+  ipa_register_cgraph_hooks ();
+  /* 1. Call the init stage to initialize 
+     the ipa_node_params and ipa_edge_args structures.  */
+  ipcp_init_stage ();
+}
+
+/* Write ipcp summary for nodes in SET.  */
+static void
+ipcp_write_summary (cgraph_node_set set)
+{
+  ipa_prop_write_jump_functions (set);
+}
+
+/* Read ipcp summary.  */
+static void
+ipcp_read_summary (void)
+{
+  ipa_prop_read_jump_functions ();
+}
+
 /* Gate for IPCP optimization.  */
 static bool
 cgraph_gate_cp (void)
@@ -1040,10 +1305,10 @@ cgraph_gate_cp (void)
   return flag_ipa_cp;
 }
 
-struct simple_ipa_opt_pass pass_ipa_cp = 
+struct ipa_opt_pass_d pass_ipa_cp =
 {
  {
-  SIMPLE_IPA_PASS,
+  IPA_PASS,
   "cp",                                /* name */
   cgraph_gate_cp,              /* gate */
   ipcp_driver,                 /* execute */
@@ -1052,9 +1317,17 @@ struct simple_ipa_opt_pass pass_ipa_cp =
   0,                           /* static_pass_number */
   TV_IPA_CONSTANT_PROP,                /* tv_id */
   0,                           /* properties_required */
-  PROP_trees,                  /* properties_provided */
+  0,                           /* properties_provided */
   0,                           /* properties_destroyed */
   0,                           /* todo_flags_start */
-  TODO_dump_cgraph | TODO_dump_func    /* todo_flags_finish */
- }
+  TODO_dump_cgraph | TODO_dump_func |
+  TODO_remove_functions /* todo_flags_finish */
+ },
+ ipcp_generate_summary,                        /* generate_summary */
+ ipcp_write_summary,                   /* write_summary */
+ ipcp_read_summary,                    /* read_summary */
+ NULL,                                 /* function_read_summary */
+ 0,                                    /* TODOs */
+ NULL,                                 /* function_transform */
+ NULL,                                 /* variable_transform */
 };