Fix merging of common target infos
diff mbox series

Message ID 20191213154309.vujpkkwefivc3akh@kam.mff.cuni.cz
State New
Headers show
Series
  • Fix merging of common target infos
Related show

Commit Message

Jan Hubicka Dec. 13, 2019, 3:43 p.m. UTC
Hi,
while looking into Firefox regression compared to gcc9 I noticed that we
often confuse common target infos when profiles get merged.  This patch
adds the missing update bits.

Honza

	* ipa-utils.c (ipa_merge_profiles): Improve dumping; merge common
	targets.

Patch
diff mbox series

Index: ipa-utils.c
===================================================================
--- ipa-utils.c	(revision 279178)
+++ ipa-utils.c	(working copy)
@@ -423,11 +423,6 @@  ipa_merge_profiles (struct cgraph_node *
   if (!src->count.initialized_p ()
       || !(src->count.ipa () == src->count))
     return;
-  if (symtab->dump_file)
-    {
-      fprintf (symtab->dump_file, "Merging profiles of %s to %s\n",
-	       src->dump_name (), dst->dump_name ());
-    }
   profile_count orig_count = dst->count;
 
   /* Either sum the profiles if both are IPA and not global0, or
@@ -451,6 +446,19 @@  ipa_merge_profiles (struct cgraph_node *
   if (dst->count == orig_count)
     return;
 
+  if (symtab->dump_file)
+    {
+      fprintf (symtab->dump_file, "Merging profiles of %s count:",
+	       src->dump_name ());
+      src->count.dump (symtab->dump_file);
+      fprintf (symtab->dump_file, " to %s count:",
+	       dst->dump_name ());
+      orig_count.dump (symtab->dump_file);
+      fprintf (symtab->dump_file, " resulting count:");
+      dst->count.dump (symtab->dump_file);
+      fprintf (symtab->dump_file, "\n");
+    }
+
   /* First handle functions with no gimple body.  */
   if (dst->thunk.thunk_p || dst->alias
       || src->thunk.thunk_p || src->alias)
@@ -516,45 +524,86 @@  ipa_merge_profiles (struct cgraph_node *
   else 
     {
       basic_block srcbb, dstbb;
+      struct cgraph_edge *e, *e2;
 
-      FOR_ALL_BB_FN (srcbb, srccfun)
+      for (e = dst->callees, e2 = src->callees; e && e2 && match;
+	   e2 = e2->next_callee, e = e->next_callee)
 	{
-	  unsigned int i;
-
-	  dstbb = BASIC_BLOCK_FOR_FN (dstcfun, srcbb->index);
-	  if (dstbb == NULL)
+	  if (gimple_bb (e->call_stmt)->index
+	      != gimple_bb (e2->call_stmt)->index)
 	    {
 	      if (symtab->dump_file)
 		fprintf (symtab->dump_file,
-			 "No matching block for bb %i.\n",
-			 srcbb->index);
+			 "Giving up; call stmt mismatch.\n");
 	      match = false;
-	      break;
 	    }
-	  if (EDGE_COUNT (srcbb->succs) != EDGE_COUNT (dstbb->succs))
+	}
+      if (e || e2)
+	{
+	  if (symtab->dump_file)
+	    fprintf (symtab->dump_file,
+		     "Giving up; number of calls differs.\n");
+	  match = false;
+	}
+      for (e = dst->indirect_calls, e2 = src->indirect_calls; e && e2 && match;
+	   e2 = e2->next_callee, e = e->next_callee)
+	{
+	  if (gimple_bb (e->call_stmt)->index
+	      != gimple_bb (e2->call_stmt)->index)
 	    {
 	      if (symtab->dump_file)
 		fprintf (symtab->dump_file,
-			 "Edge count mismatch for bb %i.\n",
-			 srcbb->index);
+			 "Giving up; indirect call stmt mismatch.\n");
 	      match = false;
-	      break;
-	    }
-	  for (i = 0; i < EDGE_COUNT (srcbb->succs); i++)
-	    {
-	      edge srce = EDGE_SUCC (srcbb, i);
-	      edge dste = EDGE_SUCC (dstbb, i);
-	      if (srce->dest->index != dste->dest->index)
-		{
-		  if (symtab->dump_file)
-		    fprintf (symtab->dump_file,
-			     "Succ edge mismatch for bb %i.\n",
-			     srce->dest->index);
-		  match = false;
-		  break;
-		}
 	    }
 	}
+      if (e || e2)
+	{
+	  if (symtab->dump_file)
+	    fprintf (symtab->dump_file,
+		     "Giving up; number of indirect calls differs.\n");
+	  match=false;
+	}
+
+      if (match)
+	FOR_ALL_BB_FN (srcbb, srccfun)
+	  {
+	    unsigned int i;
+
+	    dstbb = BASIC_BLOCK_FOR_FN (dstcfun, srcbb->index);
+	    if (dstbb == NULL)
+	      {
+		if (symtab->dump_file)
+		  fprintf (symtab->dump_file,
+			   "No matching block for bb %i.\n",
+			   srcbb->index);
+		match = false;
+		break;
+	      }
+	    if (EDGE_COUNT (srcbb->succs) != EDGE_COUNT (dstbb->succs))
+	      {
+		if (symtab->dump_file)
+		  fprintf (symtab->dump_file,
+			   "Edge count mismatch for bb %i.\n",
+			   srcbb->index);
+		match = false;
+		break;
+	      }
+	    for (i = 0; i < EDGE_COUNT (srcbb->succs); i++)
+	      {
+		edge srce = EDGE_SUCC (srcbb, i);
+		edge dste = EDGE_SUCC (dstbb, i);
+		if (srce->dest->index != dste->dest->index)
+		  {
+		    if (symtab->dump_file)
+		      fprintf (symtab->dump_file,
+			       "Succ edge mismatch for bb %i.\n",
+			       srce->dest->index);
+		    match = false;
+		    break;
+		  }
+	      }
+	  }
     }
   if (match)
     {
@@ -626,6 +675,70 @@  ipa_merge_profiles (struct cgraph_node *
 	   e2 = (e2 ? e2->next_callee : NULL), e = e->next_callee)
 	{
 	  profile_count count = gimple_bb (e->call_stmt)->count;
+	  if (copy_counts)
+	    {
+	      e->indirect_info->common_target_id
+		      = e2->indirect_info->common_target_id;
+	      e->indirect_info->common_target_probability
+		      = e2->indirect_info->common_target_probability;
+	    }
+	  else if (e->indirect_info->common_target_id
+		   || e2->indirect_info->common_target_id)
+	    {
+	      sreal scale1
+		 = e->count.ipa().to_sreal_scale (count);
+	      sreal scale2
+		 = e2->count.ipa().to_sreal_scale (count);
+
+	      if (scale1 == 0 && scale2 == 0)
+		scale1 = scale2 = 1;
+	      sreal sum = scale1 + scale2;
+	      int scaled_probability1
+		      = ((sreal)e->indirect_info->common_target_probability
+			* scale1 / sum).to_int ();
+	      int scaled_probability2
+		      = ((sreal)e2->indirect_info->common_target_probability
+			 * scale2 / sum).to_int ();
+	      if (symtab->dump_file)
+		{
+		  fprintf (symtab->dump_file,
+			   "Merging common targets %i prob %i"
+			   " and %i prob %i with scales %f %f\n",
+			   e->indirect_info->common_target_id,
+			   e->indirect_info->common_target_probability,
+			   e2->indirect_info->common_target_id,
+			   e2->indirect_info->common_target_probability,
+			   scale1.to_double (),
+			   scale2.to_double ());
+		  fprintf (symtab->dump_file, "Combined BB count ");
+		  count.dump (symtab->dump_file);
+		  fprintf (symtab->dump_file, " dst edge count ");
+		  e->count.dump (symtab->dump_file);
+		  fprintf (symtab->dump_file, " src edge count ");
+		  e2->count.dump (symtab->dump_file);
+		  fprintf (symtab->dump_file, "\n");
+		}
+	      if (e->indirect_info->common_target_id
+		  == e2->indirect_info->common_target_id)
+		e->indirect_info->common_target_probability
+		       	= scaled_probability1 + scaled_probability2;
+	      else if (!e2->indirect_info->common_target_id
+		       || scaled_probability1 > scaled_probability2)
+		e->indirect_info->common_target_probability
+		       	= scaled_probability1;
+	      else 
+		{
+		  e->indirect_info->common_target_id
+			  = e2->indirect_info->common_target_id;
+		  e->indirect_info->common_target_probability
+			  = scaled_probability2;
+		}
+	      if (symtab->dump_file)
+		fprintf (symtab->dump_file, "Merged as %i prob %i\n",
+			 e->indirect_info->common_target_id,
+			 e->indirect_info->common_target_probability);
+	    }
+
 	  /* When call is speculative, we need to re-distribute probabilities
 	     the same way as they was.  This is not really correct because
 	     in the other copy the speculation may differ; but probably it
@@ -647,8 +760,8 @@  ipa_merge_profiles (struct cgraph_node *
 		     indirect edge.  */
 		  if (!e2)
 		    {
-		      if (dump_file)
-		        fprintf (dump_file,
+		      if (symtab->dump_file)
+		        fprintf (symtab->dump_file,
 				 "Mismatch in merging indirect edges\n");
 		    }
 		  else if (!e2->speculative)