diff mbox

Fix speculation in ipa-cp, part 2

Message ID 20141117220205.GD5137@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka Nov. 17, 2014, 10:02 p.m. UTC
Hi,
this patch makes ipa-cp to handle creation of speculative edges.  This is done
same way as in inliner's updating code.  ipa-cp culd do more - use speculative
edges instead of paying all the cost to produce a full clone, but I will leave
this to Martin.

I made no attempt to tune the metrics. Inline ignore speculative edges, ipa-cp
counts them as half of the benefit of non-speculative.

Bootstrapped/regtested x86_64-linux, tested on Firefox where it produce cca 800
speculations, comitted.

Honza

	* ipa-cp.c (ipa_get_indirect_edge_target_1): Handle speculation.
	(ipa_get_indirect_edge_target): Add SPECULATIVE argument.
	(devirtualization_time_bonus): Use it.
	(ipcp_discover_new_direct_edges): Likewise.
	* ipa-inline-analysis.c (estimate_edge_devirt_benefit): Update.
	* ipa-prop.h (ipa_get_indirect_edge_target): Update prototype.
diff mbox

Patch

Index: ipa-cp.c
===================================================================
--- ipa-cp.c	(revision 217659)
+++ ipa-cp.c	(working copy)
@@ -1730,13 +1730,16 @@  ipa_get_indirect_edge_target_1 (struct c
 				vec<tree> known_csts,
 				vec<ipa_polymorphic_call_context> known_contexts,
 				vec<ipa_agg_jump_function_p> known_aggs,
-				struct ipa_agg_replacement_value *agg_reps)
+				struct ipa_agg_replacement_value *agg_reps,
+				bool *speculative)
 {
   int param_index = ie->indirect_info->param_index;
   HOST_WIDE_INT anc_offset;
   tree t;
   tree target = NULL;
 
+  *speculative = false;
+
   if (param_index == -1
       || known_csts.length () <= (unsigned int) param_index)
     return NULL_TREE;
@@ -1792,8 +1795,7 @@  ipa_get_indirect_edge_target_1 (struct c
   t = NULL;
 
   /* Try to work out value of virtual table pointer value in replacemnets.  */
-  if (!t && agg_reps && !ie->indirect_info->by_ref
-      && !ie->indirect_info->vptr_changed)
+  if (!t && agg_reps && !ie->indirect_info->by_ref)
     {
       while (agg_reps)
 	{
@@ -1811,8 +1813,7 @@  ipa_get_indirect_edge_target_1 (struct c
   /* Try to work out value of virtual table pointer value in known
      aggregate values.  */
   if (!t && known_aggs.length () > (unsigned int) param_index
-      && !ie->indirect_info->by_ref
-      && !ie->indirect_info->vptr_changed)
+      && !ie->indirect_info->by_ref)
     {
        struct ipa_agg_jump_function *agg;
        agg = known_aggs[param_index];
@@ -1836,7 +1837,9 @@  ipa_get_indirect_edge_target_1 (struct c
 		  || !possible_polymorphic_call_target_p
 		       (ie, cgraph_node::get (target)))
 		target = ipa_impossible_devirt_target (ie, target);
-	      return target;
+              *speculative = ie->indirect_info->vptr_changed;
+	      if (!*speculative)
+	        return target;
 	    }
 	}
     }
@@ -1877,11 +1880,32 @@  ipa_get_indirect_edge_target_1 (struct c
      ie->indirect_info->otr_token,
      context, &final);
   if (!final || targets.length () > 1)
-    return NULL_TREE;
-  if (targets.length () == 1)
-    target = targets[0]->decl;
+    {
+      struct cgraph_node *node;
+      if (*speculative)
+	return target;
+      if (!flag_devirtualize_speculatively || ie->speculative
+	  || !ie->maybe_hot_p ())
+	return NULL;
+      node = try_speculative_devirtualization (ie->indirect_info->otr_type,
+					       ie->indirect_info->otr_token,
+					       context);
+      if (node)
+	{
+	  *speculative = true;
+	  target = node->decl;
+	}
+      else
+	return NULL;
+    }
   else
-    target = ipa_impossible_devirt_target (ie, NULL_TREE);
+    {
+      *speculative = false;
+      if (targets.length () == 1)
+	target = targets[0]->decl;
+      else
+	target = ipa_impossible_devirt_target (ie, NULL_TREE);
+    }
 
   if (target && !possible_polymorphic_call_target_p (ie,
 						     cgraph_node::get (target)))
@@ -1899,10 +1923,11 @@  tree
 ipa_get_indirect_edge_target (struct cgraph_edge *ie,
 			      vec<tree> known_csts,
 			      vec<ipa_polymorphic_call_context> known_contexts,
-			      vec<ipa_agg_jump_function_p> known_aggs)
+			      vec<ipa_agg_jump_function_p> known_aggs,
+			      bool *speculative)
 {
   return ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
-					 known_aggs, NULL);
+					 known_aggs, NULL, speculative);
 }
 
 /* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS
@@ -1923,9 +1948,10 @@  devirtualization_time_bonus (struct cgra
       struct inline_summary *isummary;
       enum availability avail;
       tree target;
+      bool speculative;
 
       target = ipa_get_indirect_edge_target (ie, known_csts, known_contexts,
-					     known_aggs);
+					     known_aggs, &speculative);
       if (!target)
 	continue;
 
@@ -1944,12 +1970,12 @@  devirtualization_time_bonus (struct cgra
       /* FIXME: The values below need re-considering and perhaps also
 	 integrating into the cost metrics, at lest in some very basic way.  */
       if (isummary->size <= MAX_INLINE_INSNS_AUTO / 4)
-	res += 31;
+	res += 31 / ((int)speculative + 1);
       else if (isummary->size <= MAX_INLINE_INSNS_AUTO / 2)
-	res += 15;
+	res += 15 / ((int)speculative + 1);
       else if (isummary->size <= MAX_INLINE_INSNS_AUTO
 	       || DECL_DECLARED_INLINE_P (callee->decl))
-	res += 7;
+	res += 7 / ((int)speculative + 1);
     }
 
   return res;
@@ -2645,16 +2671,18 @@  ipcp_discover_new_direct_edges (struct c
   for (ie = node->indirect_calls; ie; ie = next_ie)
     {
       tree target;
+      bool speculative;
 
       next_ie = ie->next_callee;
       target = ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
-					       vNULL, aggvals);
+					       vNULL, aggvals, &speculative);
       if (target)
 	{
 	  bool agg_contents = ie->indirect_info->agg_contents;
 	  bool polymorphic = ie->indirect_info->polymorphic;
 	  int param_index = ie->indirect_info->param_index;
-	  struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target);
+	  struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target,
+								   speculative);
 	  found = true;
 
 	  if (cs && !agg_contents && !polymorphic)
Index: ipa-inline-analysis.c
===================================================================
--- ipa-inline-analysis.c	(revision 217659)
+++ ipa-inline-analysis.c	(working copy)
@@ -2986,6 +2986,7 @@  estimate_edge_devirt_benefit (struct cgr
   struct cgraph_node *callee;
   struct inline_summary *isummary;
   enum availability avail;
+  bool speculative;
 
   if (!known_vals.exists () && !known_contexts.exists ())
     return false;
@@ -2993,8 +2994,8 @@  estimate_edge_devirt_benefit (struct cgr
     return false;
 
   target = ipa_get_indirect_edge_target (ie, known_vals, known_contexts,
-					 known_aggs);
-  if (!target)
+					 known_aggs, &speculative);
+  if (!target || speculative)
     return false;
 
   /* Account for difference in cost between indirect and direct calls.  */
Index: ipa-prop.h
===================================================================
--- ipa-prop.h	(revision 217659)
+++ ipa-prop.h	(working copy)
@@ -529,7 +529,8 @@  bool ipa_propagate_indirect_call_infos (
 tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
 				   vec<tree> ,
 				   vec<ipa_polymorphic_call_context>,
-				   vec<ipa_agg_jump_function_p> );
+				   vec<ipa_agg_jump_function_p>,
+				   bool *);
 struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
 						    bool speculative = false);
 tree ipa_impossible_devirt_target (struct cgraph_edge *, tree);