Patchwork Teach IPA-CP to make calls direct based on contents of aggregates

login
register
mail settings
Submitter Martin Jambor
Date March 24, 2013, 12:15 a.m.
Message ID <20130324001514.GE16552@virgil.suse>
Download mbox | patch
Permalink /patch/230355/
State New
Headers show

Comments

Martin Jambor - March 24, 2013, 12:15 a.m.
Hi,

this is a bit of aggregate IPA-CP that I missed to submit in last
stage1 and that makes indirect call graph edges from IPA-CP clones
direct if they call a known address loaded from an aggregate
parameter.

The reason why ipa_get_indirect_edge_target is split into two is that
unlike in the inlining case, this one has to understand the
description of known aggregate values in clones which are different
from aggregate jump functions (they are quite simpler).  Otherwise the
patch is hopefully quite straightforward.

Bootstrapped and tested on x86_64-linux, OK for trunk?

Thanks,

Martin
 

2013-03-19  Martin Jambor  <mjambor@suse.cz>

	* ipa-cp.c (ipa_get_indirect_edge_target): Renamed to
	ipa_get_indirect_edge_target_1, added parameter agg_reps and ability to
	process it.
	(ipa_get_indirect_edge_target): New function.
	(devirtualization_time_bonus): New parameter known_aggs, pass it to
	ipa_get_indirect_edge_target.  Update all callers.
	(ipcp_discover_new_direct_edges): New parameter aggvals.  Pass it to
	ipa_get_indirect_edge_target_1 instead of calling
	ipa_get_indirect_edge_target.
	(create_specialized_node): Pass aggvlas to
	ipcp_discover_new_direct_edges.

testsuite/
	* gcc.dg/ipa/ipcp-agg-9.c: New test.
Jan Hubicka - March 24, 2013, 11:09 a.m.
> 
> The reason why ipa_get_indirect_edge_target is split into two is that
> unlike in the inlining case, this one has to understand the
> description of known aggregate values in clones which are different
> from aggregate jump functions (they are quite simpler).  Otherwise the
> patch is hopefully quite straightforward.

Hmm, perhaps we can commonize it a bit more?
> 
> Bootstrapped and tested on x86_64-linux, OK for trunk?

I would also suggest adding code translating calls to known constant (NULL or integer_cst) into
__builtin_trap / __bulitin_unreachable (based on Richi's preferences).  It should help code quality
(since relatively few calls are like that on Mozilla) and also it will make us to notice where
we propagate complette garbage - I still do not know of those obviously bogus calls come from
impossible type conversions (so we read past vtable) or because of some bug.
> 
> 2013-03-19  Martin Jambor  <mjambor@suse.cz>
> 
> 	* ipa-cp.c (ipa_get_indirect_edge_target): Renamed to
> 	ipa_get_indirect_edge_target_1, added parameter agg_reps and ability to
> 	process it.
> 	(ipa_get_indirect_edge_target): New function.
> 	(devirtualization_time_bonus): New parameter known_aggs, pass it to
> 	ipa_get_indirect_edge_target.  Update all callers.
> 	(ipcp_discover_new_direct_edges): New parameter aggvals.  Pass it to
> 	ipa_get_indirect_edge_target_1 instead of calling
> 	ipa_get_indirect_edge_target.
> 	(create_specialized_node): Pass aggvlas to
> 	ipcp_discover_new_direct_edges.
> 
> testsuite/
> 	* gcc.dg/ipa/ipcp-agg-9.c: New test.
> 
OK,
thanks

Honza

Patch

Index: src/gcc/ipa-cp.c
===================================================================
--- src.orig/gcc/ipa-cp.c
+++ src/gcc/ipa-cp.c
@@ -1477,14 +1477,16 @@  propagate_constants_accross_call (struct
 }
 
 /* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
-   (which can contain both constants and binfos) or KNOWN_BINFOS (which can be
-   NULL) return the destination.  */
+   (which can contain both constants and binfos), KNOWN_BINFOS, KNOWN_AGGS or
+   AGG_REPS return the destination.  The latter three can be NULL.  If AGG_REPS
+   is not NULL, KNOWN_AGGS is ignored.  */
 
-tree
-ipa_get_indirect_edge_target (struct cgraph_edge *ie,
-			      vec<tree> known_vals,
-			      vec<tree> known_binfos,
-			      vec<ipa_agg_jump_function_p> known_aggs)
+static tree
+ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
+				vec<tree> known_vals,
+				vec<tree> known_binfos,
+				vec<ipa_agg_jump_function_p> known_aggs,
+				struct ipa_agg_replacement_value *agg_reps)
 {
   int param_index = ie->indirect_info->param_index;
   HOST_WIDE_INT token, anc_offset;
@@ -1500,8 +1502,21 @@  ipa_get_indirect_edge_target (struct cgr
 
       if (ie->indirect_info->agg_contents)
 	{
-	  if (known_aggs.length ()
-	      > (unsigned int) param_index)
+	  if (agg_reps)
+	    {
+	      t = NULL;
+	      while (agg_reps)
+		{
+		  if (agg_reps->index == param_index
+		      && agg_reps->offset == ie->indirect_info->offset)
+		    {
+		      t = agg_reps->value;
+		      break;
+		    }
+		  agg_reps = agg_reps->next;
+		}
+	    }
+	  else if (known_aggs.length () > (unsigned int) param_index)
 	    {
 	      struct ipa_agg_jump_function *agg;
 	      agg = known_aggs[param_index];
@@ -1556,13 +1571,29 @@  ipa_get_indirect_edge_target (struct cgr
     }
 }
 
+
+/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
+   (which can contain both constants and binfos), KNOWN_BINFOS (which can be
+   NULL) or KNOWN_AGGS (which also can be NULL) return the destination.  */
+
+tree
+ipa_get_indirect_edge_target (struct cgraph_edge *ie,
+			      vec<tree> known_vals,
+			      vec<tree> known_binfos,
+			      vec<ipa_agg_jump_function_p> known_aggs)
+{
+  return ipa_get_indirect_edge_target_1 (ie, known_vals, known_binfos,
+					 known_aggs, NULL);
+}
+
 /* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS
    and KNOWN_BINFOS.  */
 
 static int
 devirtualization_time_bonus (struct cgraph_node *node,
 			     vec<tree> known_csts,
-			     vec<tree> known_binfos)
+			     vec<tree> known_binfos,
+			     vec<ipa_agg_jump_function_p> known_aggs)
 {
   struct cgraph_edge *ie;
   int res = 0;
@@ -1574,7 +1605,7 @@  devirtualization_time_bonus (struct cgra
       tree target;
 
       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
-					vNULL);
+					     known_aggs);
       if (!target)
 	continue;
 
@@ -1818,7 +1849,8 @@  estimate_local_effects (struct cgraph_no
       cgraph_for_node_and_aliases (node, gather_caller_stats, &stats, false);
       estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos,
 					 known_aggs_ptrs, &size, &time, &hints);
-      time -= devirtualization_time_bonus (node, known_csts, known_binfos);
+      time -= devirtualization_time_bonus (node, known_csts, known_binfos,
+					   known_aggs_ptrs);
       time -= hint_time_bonus (hints);
       time -= removable_params_cost;
       size -= stats.n_calls * removable_params_cost;
@@ -1895,7 +1927,8 @@  estimate_local_effects (struct cgraph_no
 					     known_aggs_ptrs, &size, &time,
 					     &hints);
 	  time_benefit = base_time - time
-	    + devirtualization_time_bonus (node, known_csts, known_binfos)
+	    + devirtualization_time_bonus (node, known_csts, known_binfos,
+					   known_aggs_ptrs)
 	    + hint_time_bonus (hints)
 	    + removable_params_cost + emc;
 
@@ -1957,7 +1990,8 @@  estimate_local_effects (struct cgraph_no
 						 known_aggs_ptrs, &size, &time,
 						 &hints);
 	      time_benefit = base_time - time
-		+ devirtualization_time_bonus (node, known_csts, known_binfos)
+		+ devirtualization_time_bonus (node, known_csts, known_binfos,
+					       known_aggs_ptrs)
 		+ hint_time_bonus (hints);
 	      gcc_checking_assert (size >=0);
 	      if (size == 0)
@@ -2240,7 +2274,8 @@  ipcp_propagate_stage (struct topo_info *
 
 static void
 ipcp_discover_new_direct_edges (struct cgraph_node *node,
-				vec<tree> known_vals)
+				vec<tree> known_vals,
+				struct ipa_agg_replacement_value *aggvals)
 {
   struct cgraph_edge *ie, *next_ie;
   bool found = false;
@@ -2250,7 +2285,8 @@  ipcp_discover_new_direct_edges (struct c
       tree target;
 
       next_ie = ie->next_callee;
-      target = ipa_get_indirect_edge_target (ie, known_vals, vNULL, vNULL);
+      target = ipa_get_indirect_edge_target_1 (ie, known_vals, vNULL, vNULL,
+					       aggvals);
       if (target)
 	{
 	  ipa_make_edge_direct_to_target (ie, target);
@@ -2660,7 +2696,7 @@  create_specialized_node (struct cgraph_n
   new_info->ipcp_orig_node = node;
   new_info->known_vals = known_vals;
 
-  ipcp_discover_new_direct_edges (new_node, known_vals);
+  ipcp_discover_new_direct_edges (new_node, known_vals, aggvals);
 
   callers.release ();
   return new_node;
Index: src/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c
===================================================================
--- /dev/null
+++ src/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c
@@ -0,0 +1,45 @@ 
+/* Verify that IPA-CP can make edges direct based on aggregate contents.  */
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp -fdump-ipa-inline"  } */
+
+struct S
+{
+  int i;
+  void (*f)(struct S *);
+  unsigned u;
+};
+
+struct U
+{
+  struct U *next;
+  struct S s;
+  short a[8];
+};
+
+extern void non_existent(struct S *p, int);
+
+static void hooray1 (struct S *p)
+{
+  non_existent (p, 1);
+}
+
+static __attribute__ ((noinline))
+void hiphip1 (struct S *p)
+{
+  p->f (p);
+}
+
+int test1 (void)
+{
+  struct S s;
+  s.i = 1234;
+  s.f = hooray1;
+  s.u = 1001;
+  hiphip1 (&s);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "ipa-prop: Discovered an indirect call to a known target"  "cp"  } } */
+/* { dg-final { scan-ipa-dump "hooray1\[^\\n\]*inline copy in hiphip1"  "inline"  } } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */