diff mbox series

Optimize allocations for evaluate_properties_for_edges

Message ID 20191120162328.gca2s6b7usxegm2h@kam.mff.cuni.cz
State New
Headers show
Series Optimize allocations for evaluate_properties_for_edges | expand

Commit Message

Jan Hubicka Nov. 20, 2019, 4:23 p.m. UTC
Hi,
this patch avoids malloc traffic in evaluate_properties_for_edge which
allocates vectors holding known values, aggregates and polyorphic contextes.
I made the vector allocated by a caller who can place them at stack using
auto_vec.

The patch also adds logic to avoid calculation and clearing of these vectors
for parameters which are not used.

I realize that API for evaluate_properties_for_edge became somewhat ugly
with adding a lot of additional stuff.  I will clean it up next stage1.

With this patch we still do a lot of allocations to hold
ipa_agg_value_set::items which are vectors within vectors.  I wonder how much
of this work would go away if we would further track what parameters are being
used as aggregates?

Bootstrapped/regtested x86_64-linux, will commit it shortly.

Honza

	* ipa-fnsummary.c (evaluate_conditions_for_known_args): Be
	ready for some vectors to not be allocated.
	(evaluate_properties_for_edge): Document better; make
	known_vals and known_aggs caller allocated; avoid determining
	values of parameters which are not used.
	(ipa_merge_fn_summary_after_inlining): Pre allocate known_vals and
	known_aggs.
	* ipa-inline-analysis.c (do_estimate_edge_time): Likewise.
	(do_estimate_edge_size): Likewise.
	(do_estimate_edge_hints): Likewise.
diff mbox series

Patch

Index: ipa-fnsummary.c
===================================================================
--- ipa-fnsummary.c	(revision 278464)
+++ ipa-fnsummary.c	(working copy)
@@ -329,7 +329,7 @@  evaluate_conditions_for_known_args (stru
 
   for (i = 0; vec_safe_iterate (info->conds, i, &c); i++)
     {
-      tree val;
+      tree val = NULL;
       tree res;
       int j;
       struct expr_eval_op *op;
@@ -338,14 +338,8 @@  evaluate_conditions_for_known_args (stru
          (especially for K&R style programs).  So bound check here (we assume
          known_aggs vector, if non-NULL, has the same length as
          known_vals).  */
-      gcc_checking_assert (!known_aggs.exists ()
+      gcc_checking_assert (!known_aggs.length () || !known_vals.length ()
 			   || (known_vals.length () == known_aggs.length ()));
-      if (c->operand_num >= (int) known_vals.length ())
-	{
-	  clause |= 1 << (i + predicate::first_dynamic_condition);
-	  nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
-	  continue;
-	}
 
       if (c->agg_contents)
 	{
@@ -353,19 +347,24 @@  evaluate_conditions_for_known_args (stru
 
 	  if (c->code == predicate::changed
 	      && !c->by_ref
+	      && c->operand_num < (int)known_vals.length ()
 	      && (known_vals[c->operand_num] == error_mark_node))
 	    continue;
 
-	  if (known_aggs.exists ())
+	  if (c->operand_num < (int)known_aggs.length ())
 	    {
 	      agg = &known_aggs[c->operand_num];
-	      val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num],
+	      val = ipa_find_agg_cst_for_param (agg,
+						c->operand_num
+						   < (int) known_vals.length ()
+						? known_vals[c->operand_num]
+						: NULL,
 						c->offset, c->by_ref);
 	    }
 	  else
 	    val = NULL_TREE;
 	}
-      else
+      else if (c->operand_num < (int) known_vals.length ())
 	{
 	  val = known_vals[c->operand_num];
 	  if (val == error_mark_node && c->code != predicate::changed)
@@ -491,7 +490,18 @@  evaluate_conditions_for_known_args (stru
 }
 
 
-/* Work out what conditions might be true at invocation of E.  */
+/* Work out what conditions might be true at invocation of E.
+   Compute costs for inlined edge if INLINE_P is true.
+
+   Return in CLAUSE_PTR the evaluated condistions and in NONSPEC_CLAUSE_PTR
+   (if non-NULL) conditions evaluated for nonspecialized clone called
+   in a given context.
+
+   KNOWN_VALS_PTR and KNOWN_AGGS_PTR must be non-NULL and will be filled by
+   known canstant and aggregate values of parameters.
+
+   KNOWN_CONTEXT_PTR, if non-NULL, will be filled by polymorphic call contexts
+   of parameter used by a polymorphic call.  */
 
 void
 evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
@@ -504,113 +514,141 @@  evaluate_properties_for_edge (struct cgr
 {
   struct cgraph_node *callee = e->callee->ultimate_alias_target ();
   class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
-  vec<tree> known_vals = vNULL;
   auto_vec<value_range, 32> known_value_ranges;
-  vec<ipa_agg_value_set> known_aggs = vNULL;
   class ipa_edge_args *args;
 
   if (clause_ptr)
     *clause_ptr = inline_p ? 0 : 1 << predicate::not_inlined_condition;
-  if (known_vals_ptr)
-    known_vals_ptr->create (0);
-  if (known_contexts_ptr)
-    known_contexts_ptr->create (0);
 
   if (ipa_node_params_sum
       && !e->call_stmt_cannot_inline_p
-      && ((clause_ptr && info->conds) || known_vals_ptr || known_contexts_ptr)
+      && (info->conds || known_contexts_ptr)
       && (args = IPA_EDGE_REF (e)) != NULL)
     {
       struct cgraph_node *caller;
-      class ipa_node_params *caller_parms_info, *callee_pi;
+      class ipa_node_params *caller_parms_info, *callee_pi = NULL;
       class ipa_call_summary *es = ipa_call_summaries->get (e);
       int i, count = ipa_get_cs_argument_count (args);
 
-      if (e->caller->inlined_to)
-	caller = e->caller->inlined_to;
-      else
-	caller = e->caller;
-      caller_parms_info = IPA_NODE_REF (caller);
-      callee_pi = IPA_NODE_REF (callee);
-
-      if (count && (info->conds || known_vals_ptr))
-	known_vals.safe_grow_cleared (count);
-      if (count && info->conds)
-	known_value_ranges.safe_grow_cleared (count);
-      if (count && (info->conds || known_aggs_ptr))
-	known_aggs.safe_grow_cleared (count);
-      if (count && known_contexts_ptr)
-	known_contexts_ptr->safe_grow_cleared (count);
+      if (count)
+	{
+	  if (e->caller->inlined_to)
+	    caller = e->caller->inlined_to;
+	  else
+	    caller = e->caller;
+	  caller_parms_info = IPA_NODE_REF (caller);
+          callee_pi = IPA_NODE_REF (callee);
+
+	  /* Watch for thunks.  */
+	  if (callee_pi)
+	    /* Watch for variadic functions.  */
+	    count = MIN (count, ipa_get_param_count (callee_pi));
+	}
 
       if (callee_pi)
 	for (i = 0; i < count; i++)
 	  {
 	    struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i);
-	    tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
-					     ipa_get_type (callee_pi, i));
 
-	    if (!cst && e->call_stmt
-		&& i < (int)gimple_call_num_args (e->call_stmt))
+	    if (ipa_is_param_used_by_indirect_call (callee_pi, i)
+		|| ipa_is_param_used_by_ipa_predicates (callee_pi, i))
 	      {
-		cst = gimple_call_arg (e->call_stmt, i);
-		if (!is_gimple_min_invariant (cst))
-		  cst = NULL;
-	      }
-	    if (cst)
-	      {
-		gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO);
-		if (known_vals.exists ())
-		  known_vals[i] = cst;
+		/* Determine if we know constant value of the parameter.  */
+		tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
+						 ipa_get_type (callee_pi, i));
+
+		if (!cst && e->call_stmt
+		    && i < (int)gimple_call_num_args (e->call_stmt))
+		  {
+		    cst = gimple_call_arg (e->call_stmt, i);
+		    if (!is_gimple_min_invariant (cst))
+		      cst = NULL;
+		  }
+		if (cst)
+		  {
+		    gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO);
+		    if (!known_vals_ptr->length ())
+		      vec_safe_grow_cleared (known_vals_ptr, count);
+		    (*known_vals_ptr)[i] = cst;
+		  }
+		else if (inline_p && !es->param[i].change_prob)
+		  {
+		    if (!known_vals_ptr->length ())
+		      vec_safe_grow_cleared (known_vals_ptr, count);
+		    (*known_vals_ptr)[i] = error_mark_node;
+		  }
+
+		/* If we failed to get simple constant, try value range.  */
+		if ((!cst || TREE_CODE (cst) != INTEGER_CST)
+		    && ipa_is_param_used_by_ipa_predicates (callee_pi, i))
+		  {
+		    value_range vr 
+		       = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
+						     ipa_get_type (callee_pi,
+								   i));
+		    if (!vr.undefined_p () && !vr.varying_p ())
+		      {
+			if (!known_value_ranges.length ())
+			  known_value_ranges.safe_grow_cleared (count);
+			known_value_ranges[i] = vr;
+		      }
+		  }
+
+		/* Determine known aggregate values.  */
+		ipa_agg_value_set agg
+		    = ipa_agg_value_set_from_jfunc (caller_parms_info,
+						    caller, &jf->agg);
+		if (agg.items.length ())
+		  {
+		    if (!known_aggs_ptr->length ())
+		      vec_safe_grow_cleared (known_aggs_ptr, count);
+		    (*known_aggs_ptr)[i] = agg;
+		  }
 	      }
-	    else if (inline_p && !es->param[i].change_prob)
-	      known_vals[i] = error_mark_node;
 
-	    if (known_contexts_ptr)
-	      (*known_contexts_ptr)[i]
-		= ipa_context_from_jfunc (caller_parms_info, e, i, jf);
-	
-	    known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info,
-							  caller, &jf->agg);
-            if (info->conds)
-              known_value_ranges[i] 
-                = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
-                                              ipa_get_type (callee_pi, i));
+	    /* For calls used in polymorphic calls we further determine
+	       polymorphic call context.  */
+	    if (known_contexts_ptr
+		&& ipa_is_param_used_by_polymorphic_call (callee_pi, i))
+	      {
+		ipa_polymorphic_call_context
+		   ctx = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
+		if (!ctx.useless_p ())
+		  {
+		    if (!known_contexts_ptr->length ())
+		      known_contexts_ptr->safe_grow_cleared (count);
+		    (*known_contexts_ptr)[i]
+		      = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
+		  }
+	       }
 	  }
 	else
-	  gcc_assert (callee->thunk.thunk_p);
+	  gcc_assert (!count || callee->thunk.thunk_p);
     }
-  else if (e->call_stmt && !e->call_stmt_cannot_inline_p
-	   && ((clause_ptr && info->conds) || known_vals_ptr))
+  else if (e->call_stmt && !e->call_stmt_cannot_inline_p && info->conds)
     {
       int i, count = (int)gimple_call_num_args (e->call_stmt);
 
-      if (count && (info->conds || known_vals_ptr))
-	known_vals.safe_grow_cleared (count);
       for (i = 0; i < count; i++)
 	{
 	  tree cst = gimple_call_arg (e->call_stmt, i);
 	  if (!is_gimple_min_invariant (cst))
 	    cst = NULL;
 	  if (cst)
-	    known_vals[i] = cst;
+	    {
+	      if (!known_vals_ptr->length ())
+	        vec_safe_grow_cleared (known_vals_ptr, count);
+	      (*known_vals_ptr)[i] = cst;
+	    }
 	}
     }
 
   evaluate_conditions_for_known_args (callee, inline_p,
-				      known_vals,
+				      *known_vals_ptr,
 				      known_value_ranges,
-				      known_aggs, clause_ptr,
+				      *known_aggs_ptr,
+				      clause_ptr,
 				      nonspec_clause_ptr);
-
-  if (known_vals_ptr)
-    *known_vals_ptr = known_vals;
-  else
-    known_vals.release ();
-
-  if (known_aggs_ptr)
-    *known_aggs_ptr = known_aggs;
-  else
-    ipa_release_agg_values (known_aggs);
 }
 
 
@@ -3645,8 +3683,12 @@  ipa_merge_fn_summary_after_inlining (str
   info->fp_expressions |= callee_info->fp_expressions;
 
   if (callee_info->conds)
-    evaluate_properties_for_edge (edge, true, &clause,
-				  NULL, NULL, NULL, NULL);
+    {
+      auto_vec<tree, 32> known_vals;
+      auto_vec<ipa_agg_value_set, 32> known_aggs;
+      evaluate_properties_for_edge (edge, true, &clause, NULL,
+				    &known_vals, NULL, &known_aggs);
+    }
   if (ipa_node_params_sum && callee_info->conds)
     {
       class ipa_edge_args *args = IPA_EDGE_REF (edge);
Index: ipa-inline-analysis.c
===================================================================
--- ipa-inline-analysis.c	(revision 278464)
+++ ipa-inline-analysis.c	(working copy)
@@ -186,9 +186,9 @@  do_estimate_edge_time (struct cgraph_edg
   ipa_hints hints;
   struct cgraph_node *callee;
   clause_t clause, nonspec_clause;
-  vec<tree> known_vals;
-  vec<ipa_polymorphic_call_context> known_contexts;
-  vec<ipa_agg_value_set> known_aggs;
+  auto_vec<tree, 32> known_vals;
+  auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
+  auto_vec<ipa_agg_value_set, 32> known_aggs;
   class ipa_call_summary *es = ipa_call_summaries->get (edge);
   int min_size = -1;
 
@@ -256,7 +256,6 @@  do_estimate_edge_time (struct cgraph_edg
 	     : edge->caller->count.ipa ())))
     hints |= INLINE_HINT_known_hot;
 
-  ctx.release ();
   gcc_checking_assert (size >= 0);
   gcc_checking_assert (time >= 0);
 
@@ -308,9 +307,9 @@  do_estimate_edge_size (struct cgraph_edg
   int size;
   struct cgraph_node *callee;
   clause_t clause, nonspec_clause;
-  vec<tree> known_vals;
-  vec<ipa_polymorphic_call_context> known_contexts;
-  vec<ipa_agg_value_set> known_aggs;
+  auto_vec<tree, 32> known_vals;
+  auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
+  auto_vec<ipa_agg_value_set, 32> known_aggs;
 
   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
 
@@ -333,7 +332,6 @@  do_estimate_edge_size (struct cgraph_edg
   ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
 		  	known_contexts, known_aggs, vNULL);
   ctx.estimate_size_and_time (&size, NULL, NULL, NULL, NULL);
-  ctx.release ();
   return size;
 }
 
@@ -347,9 +345,9 @@  do_estimate_edge_hints (struct cgraph_ed
   ipa_hints hints;
   struct cgraph_node *callee;
   clause_t clause, nonspec_clause;
-  vec<tree> known_vals;
-  vec<ipa_polymorphic_call_context> known_contexts;
-  vec<ipa_agg_value_set> known_aggs;
+  auto_vec<tree, 32> known_vals;
+  auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
+  auto_vec<ipa_agg_value_set, 32> known_aggs;
 
   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
 
@@ -372,7 +370,6 @@  do_estimate_edge_hints (struct cgraph_ed
   ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
 		  	known_contexts, known_aggs, vNULL);
   ctx.estimate_size_and_time (NULL, NULL, NULL, NULL, &hints);
-  ctx.release ();
   hints |= simple_edge_hints (edge);
   return hints;
 }