This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Teach IPA-CP to make calls direct based on contents of aggregates


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.

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" } } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]