diff gcc/ipa-profile.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/ipa-profile.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/ipa-profile.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Basic IPA optimizations based on profile.
-   Copyright (C) 2003-2018 Free Software Foundation, Inc.
+   Copyright (C) 2003-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -51,7 +51,6 @@
 #include "gimple-iterator.h"
 #include "ipa-utils.h"
 #include "profile.h"
-#include "params.h"
 #include "value-prof.h"
 #include "tree-inline.h"
 #include "symbol-summary.h"
@@ -135,7 +134,8 @@
 dump_histogram (FILE *file, vec<histogram_entry *> histogram)
 {
   unsigned int i;
-  gcov_type overall_time = 0, cumulated_time = 0, cumulated_size = 0, overall_size = 0;
+  gcov_type overall_time = 0, cumulated_time = 0, cumulated_size = 0,
+	    overall_size = 0;
   
   fprintf (dump_file, "Histogram:\n");
   for (i = 0; i < histogram.length (); i++)
@@ -160,7 +160,99 @@
    }
 }
 
-/* Collect histogram from CFG profiles.  */
+/* Structure containing speculative target information from profile.  */
+
+struct speculative_call_target
+{
+  speculative_call_target (unsigned int id = 0, int prob = 0)
+    : target_id (id), target_probability (prob)
+  {
+  }
+
+  /* Profile_id of target obtained from profile.  */
+  unsigned int target_id;
+  /* Probability that call will land in function with target_id.  */
+  unsigned int target_probability;
+};
+
+class speculative_call_summary
+{
+public:
+  speculative_call_summary () : speculative_call_targets ()
+  {}
+
+  auto_vec<speculative_call_target> speculative_call_targets;
+
+  void dump (FILE *f);
+
+};
+
+  /* Class to manage call summaries.  */
+
+class ipa_profile_call_summaries
+  : public call_summary<speculative_call_summary *>
+{
+public:
+  ipa_profile_call_summaries (symbol_table *table)
+    : call_summary<speculative_call_summary *> (table)
+  {}
+
+  /* Duplicate info when an edge is cloned.  */
+  virtual void duplicate (cgraph_edge *, cgraph_edge *,
+			  speculative_call_summary *old_sum,
+			  speculative_call_summary *new_sum);
+};
+
+static ipa_profile_call_summaries *call_sums = NULL;
+
+/* Dump all information in speculative call summary to F.  */
+
+void
+speculative_call_summary::dump (FILE *f)
+{
+  cgraph_node *n2;
+
+  unsigned spec_count = speculative_call_targets.length ();
+  for (unsigned i = 0; i < spec_count; i++)
+    {
+      speculative_call_target item = speculative_call_targets[i];
+      n2 = find_func_by_profile_id (item.target_id);
+      if (n2)
+	fprintf (f, "    The %i speculative target is %s with prob %3.2f\n", i,
+		 n2->dump_name (),
+		 item.target_probability / (float) REG_BR_PROB_BASE);
+      else
+	fprintf (f, "    The %i speculative target is %u with prob %3.2f\n", i,
+		 item.target_id,
+		 item.target_probability / (float) REG_BR_PROB_BASE);
+    }
+}
+
+/* Duplicate info when an edge is cloned.  */
+
+void
+ipa_profile_call_summaries::duplicate (cgraph_edge *, cgraph_edge *,
+				       speculative_call_summary *old_sum,
+				       speculative_call_summary *new_sum)
+{
+  if (!old_sum)
+    return;
+
+  unsigned old_count = old_sum->speculative_call_targets.length ();
+  if (!old_count)
+    return;
+
+  new_sum->speculative_call_targets.reserve_exact (old_count);
+  new_sum->speculative_call_targets.quick_grow_cleared (old_count);
+
+  for (unsigned i = 0; i < old_count; i++)
+    {
+      new_sum->speculative_call_targets[i]
+	= old_sum->speculative_call_targets[i];
+    }
+}
+
+/* Collect histogram and speculative target summaries from CFG profiles.  */
 
 static void
 ipa_profile_generate_summary (void)
@@ -170,9 +262,13 @@
   basic_block bb;
 
   hash_table<histogram_hash> hashtable (10);
-  
+
+  gcc_checking_assert (!call_sums);
+  call_sums = new ipa_profile_call_summaries (symtab);
+
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
-    if (ENTRY_BLOCK_PTR_FOR_FN (DECL_STRUCT_FUNCTION (node->decl))->count.ipa_p ())
+    if (ENTRY_BLOCK_PTR_FOR_FN
+	  (DECL_STRUCT_FUNCTION (node->decl))->count.ipa_p ())
       FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
 	{
 	  int time = 0;
@@ -191,38 +287,78 @@
 		     takes away bad histograms.  */
 		  if (h)
 		    {
-		      /* counter 0 is target, counter 1 is number of execution we called target,
-			 counter 2 is total number of executions.  */
-		      if (h->hvalue.counters[2])
+		      gcov_type val, count, all;
+		      struct cgraph_edge *e = node->get_edge (stmt);
+		      if (e && !e->indirect_unknown_callee)
+			continue;
+
+		      speculative_call_summary *csum
+			= call_sums->get_create (e);
+
+		      for (unsigned j = 0; j < GCOV_TOPN_VALUES; j++)
 			{
-			  struct cgraph_edge * e = node->get_edge (stmt);
-			  if (e && !e->indirect_unknown_callee)
+			  if (!get_nth_most_common_value (NULL, "indirect call",
+							  h, &val, &count, &all,
+							  j))
 			    continue;
-			  e->indirect_info->common_target_id
-			    = h->hvalue.counters [0];
-			  e->indirect_info->common_target_probability
-			    = GCOV_COMPUTE_SCALE (h->hvalue.counters [1], h->hvalue.counters [2]);
-			  if (e->indirect_info->common_target_probability > REG_BR_PROB_BASE)
+
+			  if (val == 0 || count == 0)
+			    continue;
+
+			  if (count > all)
 			    {
 			      if (dump_file)
-				fprintf (dump_file, "Probability capped to 1\n");
-			      e->indirect_info->common_target_probability = REG_BR_PROB_BASE;
+				fprintf (dump_file,
+					 "Probability capped to 1\n");
+			      count = all;
 			    }
+			  speculative_call_target item (
+			    val, GCOV_COMPUTE_SCALE (count, all));
+			  csum->speculative_call_targets.safe_push (item);
 			}
-		      gimple_remove_histogram_value (DECL_STRUCT_FUNCTION (node->decl),
-						      stmt, h);
+
+		      gimple_remove_histogram_value
+			 (DECL_STRUCT_FUNCTION (node->decl), stmt, h);
 		    }
 		}
 	      time += estimate_num_insns (stmt, &eni_time_weights);
 	      size += estimate_num_insns (stmt, &eni_size_weights);
 	    }
 	  if (bb->count.ipa_p () && bb->count.initialized_p ())
-	    account_time_size (&hashtable, histogram, bb->count.ipa ().to_gcov_type (),
+	    account_time_size (&hashtable, histogram,
+			       bb->count.ipa ().to_gcov_type (),
 			       time, size);
 	}
   histogram.qsort (cmp_counts);
 }
 
+/* Serialize the speculative summary info for LTO.  */
+
+static void
+ipa_profile_write_edge_summary (lto_simple_output_block *ob,
+				speculative_call_summary *csum)
+{
+  unsigned len = 0;
+
+  len = csum->speculative_call_targets.length ();
+
+  gcc_assert (len <= GCOV_TOPN_VALUES);
+
+  streamer_write_hwi_stream (ob->main_stream, len);
+
+  if (len)
+    {
+      unsigned spec_count = csum->speculative_call_targets.length ();
+      for (unsigned i = 0; i < spec_count; i++)
+	{
+	  speculative_call_target item = csum->speculative_call_targets[i];
+	  gcc_assert (item.target_id);
+	  streamer_write_hwi_stream (ob->main_stream, item.target_id);
+	  streamer_write_hwi_stream (ob->main_stream, item.target_probability);
+	}
+    }
+}
+
 /* Serialize the ipa info for lto.  */
 
 static void
@@ -239,10 +375,123 @@
       streamer_write_uhwi_stream (ob->main_stream, histogram[i]->time);
       streamer_write_uhwi_stream (ob->main_stream, histogram[i]->size);
     }
+
+  if (!call_sums)
+    return;
+
+  /* Serialize speculative targets information.  */
+  unsigned int count = 0;
+  lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
+  lto_symtab_encoder_iterator lsei;
+  cgraph_node *node;
+
+  for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
+       lsei_next_function_in_partition (&lsei))
+    {
+      node = lsei_cgraph_node (lsei);
+      if (node->definition && node->has_gimple_body_p ()
+	  && node->indirect_calls)
+	count++;
+    }
+
+  streamer_write_uhwi_stream (ob->main_stream, count);
+
+  /* Process all of the functions.  */
+  for (lsei = lsei_start_function_in_partition (encoder);
+       !lsei_end_p (lsei) && count; lsei_next_function_in_partition (&lsei))
+    {
+      cgraph_node *node = lsei_cgraph_node (lsei);
+      if (node->definition && node->has_gimple_body_p ()
+	  && node->indirect_calls)
+	{
+	  int node_ref = lto_symtab_encoder_encode (encoder, node);
+	  streamer_write_uhwi_stream (ob->main_stream, node_ref);
+
+	  for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+	    {
+	      speculative_call_summary *csum = call_sums->get_create (e);
+	      ipa_profile_write_edge_summary (ob, csum);
+	    }
+      }
+    }
+
   lto_destroy_simple_output_block (ob);
 }
 
-/* Deserialize the ipa info for lto.  */
+/* Dump all profile summary data for all cgraph nodes and edges to file F.  */
+
+static void
+ipa_profile_dump_all_summaries (FILE *f)
+{
+  fprintf (dump_file,
+	   "\n========== IPA-profile speculative targets: ==========\n");
+  cgraph_node *node;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+    {
+      fprintf (f, "\nSummary for node %s:\n", node->dump_name ());
+      for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+	{
+	  fprintf (f, "  Summary for %s of indirect edge %d:\n",
+		   e->caller->dump_name (), e->lto_stmt_uid);
+	  speculative_call_summary *csum = call_sums->get_create (e);
+	  csum->dump (f);
+	}
+    }
+  fprintf (f, "\n\n");
+}
+
+/* Read speculative targets information about edge for LTO WPA.  */
+
+static void
+ipa_profile_read_edge_summary (class lto_input_block *ib, cgraph_edge *edge)
+{
+  unsigned i, len;
+
+  len = streamer_read_hwi (ib);
+  gcc_assert (len <= GCOV_TOPN_VALUES);
+
+  speculative_call_summary *csum = call_sums->get_create (edge);
+
+  for (i = 0; i < len; i++)
+  {
+    unsigned int target_id = streamer_read_hwi (ib);
+    int target_probability = streamer_read_hwi (ib);
+    speculative_call_target item (target_id, target_probability);
+    csum->speculative_call_targets.safe_push (item);
+  }
+}
+
+/* Read profile speculative targets section information for LTO WPA.  */
+
+static void
+ipa_profile_read_summary_section (struct lto_file_decl_data *file_data,
+				  class lto_input_block *ib)
+{
+  if (!ib)
+    return;
+
+  lto_symtab_encoder_t encoder = file_data->symtab_node_encoder;
+
+  unsigned int count = streamer_read_uhwi (ib);
+
+  unsigned int i;
+  unsigned int index;
+  cgraph_node * node;
+
+  for (i = 0; i < count; i++)
+    {
+      index = streamer_read_uhwi (ib);
+      encoder = file_data->symtab_node_encoder;
+      node
+	= dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder, index));
+
+      for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
+	ipa_profile_read_edge_summary (ib, e);
+    }
+}
+
+/* Deserialize the IPA histogram and speculative targets summary info for LTO.
+   */
 
 static void
 ipa_profile_read_summary (void)
@@ -254,11 +503,14 @@
 
   hash_table<histogram_hash> hashtable (10);
 
+  gcc_checking_assert (!call_sums);
+  call_sums = new ipa_profile_call_summaries (symtab);
+
   while ((file_data = file_data_vec[j++]))
     {
       const char *data;
       size_t len;
-      struct lto_input_block *ib
+      class lto_input_block *ib
 	= lto_create_simple_input_block (file_data,
 					 LTO_section_ipa_profile,
 					 &data, &len);
@@ -274,6 +526,9 @@
 	      account_time_size (&hashtable, histogram,
 				 count, time, size);
 	    }
+
+	  ipa_profile_read_summary_section (file_data, ib);
+
 	  lto_destroy_simple_input_block (file_data,
 					  LTO_section_ipa_profile,
 					  ib, data, len);
@@ -326,8 +581,8 @@
       if (profile_info
 	  && !(edge->callee->count.ipa () == profile_count::zero ())
 	  && (edge->caller->frequency != NODE_FREQUENCY_UNLIKELY_EXECUTED
-	      || (edge->caller->global.inlined_to
-		  && edge->caller->global.inlined_to->frequency
+	      || (edge->caller->inlined_to
+		  && edge->caller->inlined_to->frequency
 		     != NODE_FREQUENCY_UNLIKELY_EXECUTED)))
 	  d->maybe_unlikely_executed = false;
       if (edge->count.ipa ().initialized_p ()
@@ -341,7 +596,7 @@
 	  {
 	    if (dump_file && (dump_flags & TDF_DETAILS))
 	      fprintf (dump_file, "  Called by %s that is executed once\n",
-		       edge->caller->name ());
+		       edge->caller->dump_name ());
 	    d->maybe_unlikely_executed = false;
 	    ipa_call_summary *s = ipa_call_summaries->get (edge);
 	    if (s != NULL && s->loop_depth)
@@ -356,7 +611,7 @@
 	case NODE_FREQUENCY_NORMAL:
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "  Called by %s that is normal or hot\n",
-		     edge->caller->name ());
+		     edge->caller->dump_name ());
 	  d->maybe_unlikely_executed = false;
 	  d->maybe_executed_once = false;
 	  break;
@@ -391,16 +646,16 @@
   struct ipa_propagate_frequency_data d = {node, true, true, true, true};
   bool changed = false;
 
-  /* We can not propagate anything useful about externally visible functions
+  /* We cannot propagate anything useful about externally visible functions
      nor about virtuals.  */
-  if (!node->local.local
+  if (!node->local
       || node->alias
       || (opt_for_fn (node->decl, flag_devirtualize)
 	  && DECL_VIRTUAL_P (node->decl)))
     return false;
   gcc_assert (node->analyzed);
   if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Processing frequency %s\n", node->name ());
+    fprintf (dump_file, "Processing frequency %s\n", node->dump_name ());
 
   node->call_for_symbol_and_aliases (ipa_propagate_frequency_1, &d,
 				     true);
@@ -411,7 +666,7 @@
        node->only_called_at_startup = true;
        if (dump_file)
          fprintf (dump_file, "Node %s promoted to only called at startup.\n",
-		  node->name ());
+		  node->dump_name ());
        changed = true;
     }
   if ((d.only_called_at_exit && !d.only_called_at_startup)
@@ -420,7 +675,7 @@
        node->only_called_at_exit = true;
        if (dump_file)
          fprintf (dump_file, "Node %s promoted to only called at exit.\n",
-		  node->name ());
+		  node->dump_name ());
        changed = true;
     }
 
@@ -439,7 +694,7 @@
 	    {
 	      if (dump_file)
 		fprintf (dump_file, "Node %s promoted to hot.\n",
-			 node->name ());
+			 node->dump_name ());
 	      node->frequency = NODE_FREQUENCY_HOT;
 	      return true;
 	    }
@@ -449,7 +704,7 @@
 	{
 	  if (dump_file)
 	    fprintf (dump_file, "Node %s reduced to normal.\n",
-		     node->name ());
+		     node->dump_name ());
 	  node->frequency = NODE_FREQUENCY_NORMAL;
 	  changed = true;
 	}
@@ -463,7 +718,7 @@
       node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
       if (dump_file)
 	fprintf (dump_file, "Node %s promoted to unlikely executed.\n",
-		 node->name ());
+		 node->dump_name ());
       changed = true;
     }
   else if (d.maybe_executed_once && node->frequency != NODE_FREQUENCY_EXECUTED_ONCE)
@@ -471,12 +726,33 @@
       node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
       if (dump_file)
 	fprintf (dump_file, "Node %s promoted to executed once.\n",
-		 node->name ());
+		 node->dump_name ());
       changed = true;
     }
   return changed;
 }
 
+/* Check that number of arguments of N agrees with E.
+   Be conservative when summaries are not present.  */
+
+static bool
+check_argument_count (struct cgraph_node *n, struct cgraph_edge *e)
+{
+  if (!ipa_node_params_sum || !ipa_edge_args_sum)
+    return true;
+  class ipa_node_params *info = IPA_NODE_REF (n->function_symbol ());
+  if (!info)
+    return true;
+  ipa_edge_args *e_info = IPA_EDGE_REF (e);
+  if (!e_info)
+    return true;
+  if (ipa_get_param_count (info) != ipa_get_cs_argument_count (e_info)
+      && (ipa_get_param_count (info) >= ipa_get_cs_argument_count (e_info)
+	  || !stdarg_p (TREE_TYPE (n->decl))))
+    return false;
+  return true;
+}
+
 /* Simple ipa profile pass propagating frequencies across the callgraph.  */
 
 static unsigned int
@@ -492,6 +768,7 @@
   int nindirect = 0, ncommon = 0, nunknown = 0, nuseless = 0, nconverted = 0;
   int nmismatch = 0, nimpossible = 0;
   bool node_map_initialized = false;
+  gcov_type threshold;
 
   if (dump_file)
     dump_histogram (dump_file, histogram);
@@ -500,14 +777,12 @@
       overall_time += histogram[i]->count * histogram[i]->time;
       overall_size += histogram[i]->size;
     }
+  threshold = 0;
   if (overall_time)
     {
-      gcov_type threshold;
-
       gcc_assert (overall_size);
 
-      cutoff = (overall_time * PARAM_VALUE (HOT_BB_COUNT_WS_PERMILLE) + 500) / 1000;
-      threshold = 0;
+      cutoff = (overall_time * param_hot_bb_count_ws_permille + 500) / 1000;
       for (i = 0; cumulated < cutoff; i++)
 	{
 	  cumulated += histogram[i]->count * histogram[i]->time;
@@ -533,21 +808,31 @@
 		   cumulated_size * 100.0 / overall_size);
 	}
 
-      if (threshold > get_hot_bb_threshold ()
-	  || in_lto_p)
+      if (in_lto_p)
 	{
 	  if (dump_file)
-	    fprintf (dump_file, "Threshold updated.\n");
+	    fprintf (dump_file, "Setting hotness threshold in LTO mode.\n");
           set_hot_bb_threshold (threshold);
 	}
     }
   histogram.release ();
   histogram_pool.release ();
 
-  /* Produce speculative calls: we saved common traget from porfiling into
-     e->common_target_id.  Now, at link time, we can look up corresponding
+  /* Produce speculative calls: we saved common target from profiling into
+     e->target_id.  Now, at link time, we can look up corresponding
      function node and produce speculative call.  */
 
+  gcc_checking_assert (call_sums);
+
+  if (dump_file)
+    {
+      if (!node_map_initialized)
+	init_node_map (false);
+      node_map_initialized = true;
+
+      ipa_profile_dump_all_summaries (dump_file);
+    }
+
   FOR_EACH_DEFINED_FUNCTION (n)
     {
       bool update = false;
@@ -559,107 +844,130 @@
 	{
 	  if (n->count.initialized_p ())
 	    nindirect++;
-	  if (e->indirect_info->common_target_id)
+
+	  speculative_call_summary *csum = call_sums->get_create (e);
+	  unsigned spec_count = csum->speculative_call_targets.length ();
+	  if (spec_count)
 	    {
 	      if (!node_map_initialized)
-	        init_node_map (false);
+		init_node_map (false);
 	      node_map_initialized = true;
 	      ncommon++;
-	      n2 = find_func_by_profile_id (e->indirect_info->common_target_id);
-	      if (n2)
+
+	      if (in_lto_p)
 		{
 		  if (dump_file)
 		    {
-		      fprintf (dump_file, "Indirect call -> direct call from"
-			       " other module %s => %s, prob %3.2f\n",
-			       n->dump_name (),
-			       n2->dump_name (),
-			       e->indirect_info->common_target_probability
-			       / (float)REG_BR_PROB_BASE);
+		      fprintf (dump_file,
+			       "Updating hotness threshold in LTO mode.\n");
+		      fprintf (dump_file, "Updated min count: %" PRId64 "\n",
+			       (int64_t) threshold / spec_count);
 		    }
-		  if (e->indirect_info->common_target_probability
-		      < REG_BR_PROB_BASE / 2)
+		  set_hot_bb_threshold (threshold / spec_count);
+		}
+
+	      unsigned speculative_id = 0;
+	      profile_count orig = e->count;
+	      for (unsigned i = 0; i < spec_count; i++)
+		{
+		  speculative_call_target item
+		    = csum->speculative_call_targets[i];
+		  n2 = find_func_by_profile_id (item.target_id);
+		  if (n2)
 		    {
-		      nuseless++;
-		      if (dump_file)
-			fprintf (dump_file,
-				 "Not speculating: probability is too low.\n");
-		    }
-		  else if (!e->maybe_hot_p ())
-		    {
-		      nuseless++;
-		      if (dump_file)
-			fprintf (dump_file,
-				 "Not speculating: call is cold.\n");
-		    }
-		  else if (n2->get_availability () <= AVAIL_INTERPOSABLE
-			   && n2->can_be_discarded_p ())
-		    {
-		      nuseless++;
 		      if (dump_file)
-			fprintf (dump_file,
-				 "Not speculating: target is overwritable "
-				 "and can be discarded.\n");
-		    }
-		  else if (ipa_node_params_sum && ipa_edge_args_sum
-			   && (!vec_safe_is_empty
-			       (IPA_NODE_REF (n2)->descriptors))
-			   && ipa_get_param_count (IPA_NODE_REF (n2))
-			      != ipa_get_cs_argument_count (IPA_EDGE_REF (e))
-			    && (ipa_get_param_count (IPA_NODE_REF (n2))
-				>= ipa_get_cs_argument_count (IPA_EDGE_REF (e))
-				|| !stdarg_p (TREE_TYPE (n2->decl))))
-		    {
-		      nmismatch++;
-		      if (dump_file)
-			fprintf (dump_file,
-				 "Not speculating: "
-				 "parameter count mistmatch\n");
-		    }
-		  else if (e->indirect_info->polymorphic
-			   && !opt_for_fn (n->decl, flag_devirtualize)
-			   && !possible_polymorphic_call_target_p (e, n2))
-		    {
-		      nimpossible++;
-		      if (dump_file)
-			fprintf (dump_file,
-				 "Not speculating: "
-				 "function is not in the polymorphic "
-				 "call target list\n");
+			{
+			  fprintf (dump_file,
+				   "Indirect call -> direct call from"
+				   " other module %s => %s, prob %3.2f\n",
+				   n->dump_name (),
+				   n2->dump_name (),
+				   item.target_probability
+				     / (float) REG_BR_PROB_BASE);
+			}
+		      if (item.target_probability
+		 	  < REG_BR_PROB_BASE / GCOV_TOPN_VALUES / 2)
+			{
+			  nuseless++;
+			  if (dump_file)
+			    fprintf (dump_file,
+				     "Not speculating: "
+				     "probability is too low.\n");
+			}
+		      else if (!e->maybe_hot_p ())
+			{
+			  nuseless++;
+			  if (dump_file)
+			    fprintf (dump_file,
+				     "Not speculating: call is cold.\n");
+			}
+		      else if (n2->get_availability () <= AVAIL_INTERPOSABLE
+			       && n2->can_be_discarded_p ())
+			{
+			  nuseless++;
+			  if (dump_file)
+			    fprintf (dump_file,
+				     "Not speculating: target is overwritable "
+				     "and can be discarded.\n");
+			}
+		      else if (!check_argument_count (n2, e))
+			{
+			  nmismatch++;
+			  if (dump_file)
+			    fprintf (dump_file,
+				     "Not speculating: "
+				     "parameter count mismatch\n");
+			}
+		      else if (e->indirect_info->polymorphic
+			       && !opt_for_fn (n->decl, flag_devirtualize)
+			       && !possible_polymorphic_call_target_p (e, n2))
+			{
+			  nimpossible++;
+			  if (dump_file)
+			    fprintf (dump_file,
+				     "Not speculating: "
+				     "function is not in the polymorphic "
+				     "call target list\n");
+			}
+		      else
+			{
+			  /* Target may be overwritable, but profile says that
+			     control flow goes to this particular implementation
+			     of N2.  Speculate on the local alias to allow
+			     inlining.  */
+			  if (!n2->can_be_discarded_p ())
+			    {
+			      cgraph_node *alias;
+			      alias = dyn_cast<cgraph_node *>
+				   (n2->noninterposable_alias ());
+			      if (alias)
+				n2 = alias;
+			    }
+			  nconverted++;
+			  profile_probability prob
+				 = profile_probability::from_reg_br_prob_base
+					(item.target_probability).adjusted ();
+			  e->make_speculative (n2,
+					       orig.apply_probability (prob),
+					       speculative_id);
+			  update = true;
+			  speculative_id++;
+			}
 		    }
 		  else
 		    {
-		      /* Target may be overwritable, but profile says that
-			 control flow goes to this particular implementation
-			 of N2.  Speculate on the local alias to allow inlining.
-		       */
-		      if (!n2->can_be_discarded_p ())
-			{
-			  cgraph_node *alias;
-			  alias = dyn_cast<cgraph_node *> (n2->noninterposable_alias ());
-			  if (alias)
-			    n2 = alias;
-			}
-		      nconverted++;
-		      e->make_speculative
-			(n2,
-			 e->count.apply_probability
-				     (e->indirect_info->common_target_probability));
-		      update = true;
+		      if (dump_file)
+			fprintf (dump_file,
+				 "Function with profile-id %i not found.\n",
+				 item.target_id);
+		      nunknown++;
 		    }
 		}
-	      else
-		{
-		  if (dump_file)
-		    fprintf (dump_file, "Function with profile-id %i not found.\n",
-			     e->indirect_info->common_target_id);
-		  nunknown++;
-		}
 	    }
-	 }
-       if (update)
-	 ipa_update_overall_fn_summary (n);
-     }
+	}
+      if (update)
+	ipa_update_overall_fn_summary (n);
+    }
   if (node_map_initialized)
     del_node_map ();
   if (dump_file && nindirect)
@@ -683,12 +991,12 @@
   order_pos = ipa_reverse_postorder (order);
   for (i = order_pos - 1; i >= 0; i--)
     {
-      if (order[i]->local.local
+      if (order[i]->local
 	  && opt_for_fn (order[i]->decl, flag_ipa_profile)
 	  && ipa_propagate_frequency (order[i]))
 	{
 	  for (e = order[i]->callees; e; e = e->next_callee)
-	    if (e->callee->local.local && !e->callee->aux)
+	    if (e->callee->local && !e->callee->aux)
 	      {
 	        something_changed = true;
 	        e->callee->aux = (void *)1;
@@ -707,7 +1015,7 @@
 	      && ipa_propagate_frequency (order[i]))
 	    {
 	      for (e = order[i]->callees; e; e = e->next_callee)
-		if (e->callee->local.local && !e->callee->aux)
+		if (e->callee->local && !e->callee->aux)
 		  {
 		    something_changed = true;
 		    e->callee->aux = (void *)1;
@@ -717,6 +1025,13 @@
 	}
     }
   free (order);
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    symtab->dump (dump_file);
+
+  delete call_sums;
+  call_sums = NULL;
+
   return 0;
 }