[PATCH 2/2] ipa-cp: Better representation of aggregate values in call contexts

Martin Jambor mjambor@suse.cz
Tue Aug 30 17:06:06 GMT 2022


Hi

this patch extends the previous one by using the same data structure
to represent aggregate values in classes ipa_auto_call_arg_values and
ipa_call_arg_values.

This usually simplifies handling and makes allocations of memory much
cheaper because only a single vectore is needed, as opposed to vectors
with each element pointing at other vecs.  The only functions which
unfortunately are a bit more complec are estimate_local_effects in
ipa-cp.cc and ipa_call_context::equal_to but I hope not too much - the
latter could probably be shorteneed at the expense of readability.

The patch removes types ipa_agg_value ipa_agg_value_set which is no
longer used with it.  This means that we could replace the "_argagg_"
part of the types introduced by the previous patches with more
reasonable "_agg_" - possibly as a follow-up patch.

Bootstrapped, LTO-bootstrapped and tested on x86_64-linux (and a
slightly older version also on aarch64-linux).  LTO-profiledbootstrap is
currently underway.  Given the size of the patch I assume there will be
concerns/questions but I'm looking for an approval to commit a version
of this.

Thanks,

Martin


gcc/ChangeLog:

2022-08-26  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.h (ipa_agg_value): Remove type.
	(ipa_agg_value_set): Likewise.
	(ipa_copy_agg_values): Remove function.
	(ipa_release_agg_values): Likewise.
	(ipa_auto_call_arg_values) Add a forward declaration.
	(ipa_call_arg_values): Likewise.
	(class ipa_argagg_value_list): New constructors, added member function
	value_for_index_p.
	(class ipa_auto_call_arg_values): Removed the destructor and member
	function safe_aggval_at.  Use ipa_argagg_values for m_known_aggs.
	(class ipa_call_arg_values): Removed member function safe_aggval_at.
	Use ipa_argagg_values for m_known_aggs.
	(ipa_get_indirect_edge_target): Removed declaration.
	(ipa_find_agg_cst_for_param): Likewise.
	(ipa_find_agg_cst_from_init): New declaration.
	(ipa_agg_value_from_jfunc): Likewise.
	(ipa_agg_value_set_from_jfunc): Removed declaration.
	(ipa_push_agg_values_from_jfunc): New declaration.
	* ipa-cp.cc (ipa_agg_value_from_node): Renamed to
	ipa_agg_value_from_jfunc, made public.
	(ipa_agg_value_set_from_jfunc): Removed.
	(ipa_push_agg_values_from_jfunc): New function.
	(ipa_get_indirect_edge_target_1): Removed known_aggs parameter, use
	avs for this purpose too.
	(ipa_get_indirect_edge_target): Removed the overload working on
	ipa_auto_call_arg_values, use ipa_argagg_value_list in the remaining
	one.
	(devirtualization_time_bonus): Use ipa_argagg_value_list and
	ipa_get_indirect_edge_target_1 instead of
	ipa_get_indirect_edge_target.
	(context_independent_aggregate_values): Removed function.
	(gather_context_independent_values): Work on ipa_argagg_value_list.
	(estimate_local_effects): Likewise, define some iterator variables
	only in the construct where necessary.
	(ipcp_discover_new_direct_edges): Adjust the call to
	ipa_get_indirect_edge_target_1.
	(push_agg_values_for_index_from_edge): Adjust the call
	ipa_agg_value_from_node which has been renamed to
	ipa_agg_value_from_jfunc.
	* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Work on
	ipa_argagg_value_list.
	(evaluate_properties_for_edge): Replace manual filling in aggregate
	values with call to ipa_push_agg_values_from_jfunc.
	(estimate_calls_size_and_time): Work on ipa_argagg_value_list.
	(ipa_cached_call_context::duplicate_from): Likewise.
	(ipa_cached_call_context::release): Likewise.
	(ipa_call_context::equal_to): Likewise.
	* ipa-prop.cc (ipa_find_agg_cst_from_init): Make public.
	(ipa_find_agg_cst_for_param): Removed function.
	(ipa_find_agg_cst_from_jfunc_items): New function.
	(try_make_edge_direct_simple_call): Replace calls to
	ipa_agg_value_set_from_jfunc and ipa_find_agg_cst_for_param with
	ipa_find_agg_cst_from_init and ipa_find_agg_cst_from_jfunc_items.
	(try_make_edge_direct_virtual_call): Replace calls to
	ipa_agg_value_set_from_jfunc and ipa_find_agg_cst_for_param with
	simple query of constant jump function and a call to
	ipa_find_agg_cst_from_jfunc_items.
	(ipa_auto_call_arg_values::~ipa_auto_call_arg_values): Removed.
---
 gcc/ipa-cp.cc        | 234 +++++++++++++++++--------------------------
 gcc/ipa-fnsummary.cc | 105 ++++++++++---------
 gcc/ipa-prop.cc      | 110 ++++++--------------
 gcc/ipa-prop.h       | 172 +++++++------------------------
 4 files changed, 218 insertions(+), 403 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 024f8c06b5d..098392d9b90 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1973,10 +1973,9 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
    NODE and INFO describes the caller node or the one it is inlined to, and
    its related info.  */
 
-static tree
-ipa_agg_value_from_node (class ipa_node_params *info,
-			 struct cgraph_node *node,
-			 const ipa_agg_jf_item *item)
+tree
+ipa_agg_value_from_jfunc (ipa_node_params *info, cgraph_node *node,
+			  const ipa_agg_jf_item *item)
 {
   tree value = NULL_TREE;
   int src_idx;
@@ -2059,37 +2058,38 @@ ipa_agg_value_from_node (class ipa_node_params *info,
 				  item->type);
 }
 
-/* Determine whether AGG_JFUNC evaluates to a set of known constant value for
-   an aggregate and if so, return it.  Otherwise return an empty set.  NODE
-   and INFO describes the caller node or the one it is inlined to, and its
-   related info.  */
+/* Process all items in AGG_JFUNC relative to caller (or the node the original
+  caller is inlined to) NODE which described by INFO and push the results to
+  RES as describing values passed in parameter DST_INDEX.  */
 
-struct ipa_agg_value_set
-ipa_agg_value_set_from_jfunc (class ipa_node_params *info, cgraph_node *node,
-			      struct ipa_agg_jump_function *agg_jfunc)
+void
+ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node,
+				ipa_agg_jump_function *agg_jfunc,
+				unsigned dst_index,
+				vec<ipa_argagg_value> *res)
 {
-  struct ipa_agg_value_set agg;
-  struct ipa_agg_jf_item *item;
-  int i;
+  unsigned prev_unit_offset = 0;
+  bool first = true;
 
-  agg.items = vNULL;
-  agg.by_ref = agg_jfunc->by_ref;
-
-  FOR_EACH_VEC_SAFE_ELT (agg_jfunc->items, i, item)
+  for (const ipa_agg_jf_item &item : agg_jfunc->items)
     {
-      tree value = ipa_agg_value_from_node (info, node, item);
+      tree value = ipa_agg_value_from_jfunc (info, node, &item);
+      if (!value)
+	continue;
 
-      if (value)
-	{
-	  struct ipa_agg_value value_item;
+      ipa_argagg_value iav;
+      iav.value = value;
+      iav.unit_offset = item.offset / BITS_PER_UNIT;
+      iav.index = dst_index;
+      iav.by_ref = agg_jfunc->by_ref;
 
-	  value_item.offset = item->offset;
-	  value_item.value = value;
+      gcc_assert (first
+		  || iav.unit_offset > prev_unit_offset);
+      prev_unit_offset = iav.unit_offset;
+      first = false;
 
-	  agg.items.safe_push (value_item);
-	}
+      res->safe_push (iav);
     }
-  return agg;
 }
 
 /* If checking is enabled, verify that no lattice is in the TOP state, i.e. not
@@ -3238,8 +3238,7 @@ static tree
 ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 				const vec<tree> &known_csts,
 				const vec<ipa_polymorphic_call_context> &known_contexts,
-				const vec<ipa_agg_value_set> &known_aggs,
-				const ipa_argagg_value_list *avs,
+				const ipa_argagg_value_list &avs,
 				bool *speculative)
 {
   int param_index = ie->indirect_info->param_index;
@@ -3259,31 +3258,16 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
       if (ie->indirect_info->agg_contents)
 	{
 	  t = NULL;
-	  if (avs && ie->indirect_info->guaranteed_unmodified)
-	    t = avs->get_value (param_index,
-				ie->indirect_info->offset / BITS_PER_UNIT,
-				ie->indirect_info->by_ref);
-	  if (!t)
-	    {
-	      const ipa_agg_value_set *agg;
-	      if (known_aggs.length () > (unsigned int) param_index)
-		agg = &known_aggs[param_index];
-	      else
-		agg = NULL;
-	      bool from_global_constant;
-	      t = ipa_find_agg_cst_for_param (agg,
-					      (unsigned) param_index
-						 < known_csts.length ()
-					      ? known_csts[param_index]
-					      : NULL,
-					      ie->indirect_info->offset,
-					      ie->indirect_info->by_ref,
-					      &from_global_constant);
-	      if (t
-		  && !from_global_constant
-		  && !ie->indirect_info->guaranteed_unmodified)
-		t = NULL_TREE;
-	    }
+	  if ((unsigned) param_index < known_csts.length ()
+	      && known_csts[param_index])
+	    t = ipa_find_agg_cst_from_init (known_csts[param_index],
+					    ie->indirect_info->offset,
+					    ie->indirect_info->by_ref);
+
+	  if (!t && ie->indirect_info->guaranteed_unmodified)
+	    t = avs.get_value (param_index,
+			       ie->indirect_info->offset / BITS_PER_UNIT,
+			       ie->indirect_info->by_ref);
 	}
       else if ((unsigned) param_index < known_csts.length ())
 	t = known_csts[param_index];
@@ -3300,28 +3284,22 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
     return NULL_TREE;
 
   gcc_assert (!ie->indirect_info->agg_contents);
+  gcc_assert (!ie->indirect_info->by_ref);
   anc_offset = ie->indirect_info->offset;
 
   t = NULL;
 
-  /* Try to work out value of virtual table pointer value in replacements.  */
-  if (!t && avs && !ie->indirect_info->by_ref)
-    t = avs->get_value (param_index,
-			ie->indirect_info->offset / BITS_PER_UNIT,
-			true);
+  if ((unsigned) param_index < known_csts.length ()
+      && known_csts[param_index])
+    t = ipa_find_agg_cst_from_init (known_csts[param_index],
+				    ie->indirect_info->offset, true);
 
-  /* 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)
-    {
-      const ipa_agg_value_set *agg = &known_aggs[param_index];
-      t = ipa_find_agg_cst_for_param (agg,
-				      (unsigned) param_index
-					 < known_csts.length ()
-				      ? known_csts[param_index] : NULL,
-				      ie->indirect_info->offset, true);
-    }
+  /* Try to work out value of virtual table pointer value in replacements.  */
+  /* or known aggregate values.  */
+  if (!t)
+    t = avs.get_value (param_index,
+		       ie->indirect_info->offset / BITS_PER_UNIT,
+		       true);
 
   /* If we found the virtual table pointer, lookup the target.  */
   if (t)
@@ -3440,23 +3418,10 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie,
 			      ipa_call_arg_values *avals,
 			      bool *speculative)
 {
+  ipa_argagg_value_list avl (avals);
   return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals,
 					 avals->m_known_contexts,
-					 avals->m_known_aggs,
-					 NULL, speculative);
-}
-
-/* The same functionality as above overloaded for ipa_auto_call_arg_values.  */
-
-tree
-ipa_get_indirect_edge_target (struct cgraph_edge *ie,
-			      ipa_auto_call_arg_values *avals,
-			      bool *speculative)
-{
-  return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals,
-					 avals->m_known_contexts,
-					 avals->m_known_aggs,
-					 NULL, speculative);
+					 avl, speculative);
 }
 
 /* Calculate devirtualization time bonus for NODE, assuming we know information
@@ -3477,7 +3442,10 @@ devirtualization_time_bonus (struct cgraph_node *node,
       tree target;
       bool speculative;
 
-      target = ipa_get_indirect_edge_target (ie, avals, &speculative);
+      ipa_argagg_value_list avl (avals);
+      target = ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals,
+					       avals->m_known_contexts,
+					       avl, &speculative);
       if (!target)
 	continue;
 
@@ -3613,32 +3581,6 @@ good_cloning_opportunity_p (struct cgraph_node *node, sreal time_benefit,
     }
 }
 
-/* Return all context independent values from aggregate lattices in PLATS in a
-   vector.  Return NULL if there are none.  */
-
-static vec<ipa_agg_value>
-context_independent_aggregate_values (class ipcp_param_lattices *plats)
-{
-  vec<ipa_agg_value> res = vNULL;
-
-  if (plats->aggs_bottom
-      || plats->aggs_contain_variable
-      || plats->aggs_count == 0)
-    return vNULL;
-
-  for (struct ipcp_agg_lattice *aglat = plats->aggs;
-       aglat;
-       aglat = aglat->next)
-    if (aglat->is_single_const ())
-      {
-	struct ipa_agg_value item;
-	item.offset = aglat->offset;
-	item.value = aglat->values->value;
-	res.safe_push (item);
-      }
-  return res;
-}
-
 /* Grow vectors in AVALS and fill them with information about values of
    parameters that are known to be independent of the context.  Only calculate
    m_known_aggs if CALCULATE_AGGS is true.  INFO describes the function.  If
@@ -3658,8 +3600,6 @@ gather_context_independent_values (class ipa_node_params *info,
 
   avals->m_known_vals.safe_grow_cleared (count, true);
   avals->m_known_contexts.safe_grow_cleared (count, true);
-  if (calculate_aggs)
-    avals->m_known_aggs.safe_grow_cleared (count, true);
 
   if (removable_params_cost)
     *removable_params_cost = 0;
@@ -3694,16 +3634,7 @@ gather_context_independent_values (class ipa_node_params *info,
 	avals->m_known_contexts[i] = ctxlat->values->value;
 
       if (calculate_aggs)
-	{
-	  vec<ipa_agg_value> agg_items;
-	  struct ipa_agg_value_set *agg;
-
-	  agg_items = context_independent_aggregate_values (plats);
-	  agg = &avals->m_known_aggs[i];
-	  agg->items = agg_items;
-	  agg->by_ref = plats->aggs_by_ref;
-	  ret |= !agg_items.is_empty ();
-	}
+	ret |= push_agg_values_from_plats (plats, i, 0, &avals->m_known_aggs);
     }
 
   return ret;
@@ -3774,7 +3705,7 @@ static void
 estimate_local_effects (struct cgraph_node *node)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
-  int i, count = ipa_get_param_count (info);
+  int count = ipa_get_param_count (info);
   bool always_const;
   int removable_params_cost;
 
@@ -3840,7 +3771,7 @@ estimate_local_effects (struct cgraph_node *node)
 
     }
 
-  for (i = 0; i < count; i++)
+  for (int i = 0; i < count; i++)
     {
       class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
       ipcp_lattice<tree> *lat = &plats->itself;
@@ -3874,7 +3805,7 @@ estimate_local_effects (struct cgraph_node *node)
       avals.m_known_vals[i] = NULL_TREE;
     }
 
-  for (i = 0; i < count; i++)
+  for (int i = 0; i < count; i++)
     {
       class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
 
@@ -3909,30 +3840,49 @@ estimate_local_effects (struct cgraph_node *node)
       avals.m_known_contexts[i] = ipa_polymorphic_call_context ();
     }
 
-  for (i = 0; i < count; i++)
+  unsigned all_ctx_len = avals.m_known_aggs.length ();
+  auto_vec<ipa_argagg_value, 32> all_ctx;
+  all_ctx.reserve_exact (all_ctx_len);
+  all_ctx.splice (avals.m_known_aggs);
+  avals.m_known_aggs.safe_grow_cleared (all_ctx_len + 1);
+
+  unsigned j = 0;
+  for (int index = 0; index < count; index++)
     {
-      class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+      class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, index);
 
       if (plats->aggs_bottom || !plats->aggs)
 	continue;
 
-      ipa_agg_value_set *agg = &avals.m_known_aggs[i];
       for (ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next)
 	{
 	  ipcp_value<tree> *val;
 	  if (aglat->bottom || !aglat->values
-	      /* If the following is true, the one value is in known_aggs.  */
+	      /* If the following is true, the one value is already part of all
+		 context estimations.  */
 	      || (!plats->aggs_contain_variable
 		  && aglat->is_single_const ()))
 	    continue;
 
+	  unsigned unit_offset = aglat->offset / BITS_PER_UNIT;
+	  while (j < all_ctx_len
+		 && (all_ctx[j].index < index
+		     || (all_ctx[j].index == index
+			 && all_ctx[j].unit_offset < unit_offset)))
+	    {
+	      avals.m_known_aggs[j] = all_ctx[j];
+	      j++;
+	    }
+
+	  for (unsigned k = j; k < all_ctx_len; k++)
+	    avals.m_known_aggs[k+1] = all_ctx[k];
+
 	  for (val = aglat->values; val; val = val->next)
 	    {
-	      struct ipa_agg_value item;
-
-	      item.offset = aglat->offset;
-	      item.value = val->value;
-	      agg->items.safe_push (item);
+	      avals.m_known_aggs[j].value = val->value;
+	      avals.m_known_aggs[j].unit_offset = unit_offset;
+	      avals.m_known_aggs[j].index = index;
+	      avals.m_known_aggs[j].by_ref = plats->aggs_by_ref;
 
 	      perform_estimation_of_a_value (node, &avals,
 					     removable_params_cost, 0, val);
@@ -3942,7 +3892,7 @@ estimate_local_effects (struct cgraph_node *node)
 		  fprintf (dump_file, " - estimates for value ");
 		  print_ipcp_constant_value (dump_file, val->value);
 		  fprintf (dump_file, " for ");
-		  ipa_dump_param (dump_file, info, i);
+		  ipa_dump_param (dump_file, info, index);
 		  fprintf (dump_file, "[%soffset: " HOST_WIDE_INT_PRINT_DEC
 			   "]: time_benefit: %g, size: %i\n",
 			   plats->aggs_by_ref ? "ref " : "",
@@ -3950,8 +3900,6 @@ estimate_local_effects (struct cgraph_node *node)
 			   val->local_time_benefit.to_double (),
 			   val->local_size_cost);
 		}
-
-	      agg->items.pop ();
 	    }
 	}
     }
@@ -4348,7 +4296,7 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
       next_ie = ie->next_callee;
       ipa_argagg_value_list avs (aggvals);
       target = ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
-					       vNULL, &avs, &speculative);
+					       avs, &speculative);
       if (target)
 	{
 	  bool agg_contents = ie->indirect_info->agg_contents;
@@ -5777,8 +5725,8 @@ push_agg_values_for_index_from_edge (struct cgraph_edge *cs, int index,
 					 agg_jf.value.pass_through.operand,
 					 agg_jf.type);
       else
-	value = ipa_agg_value_from_node (caller_info, cs->caller,
-					 &agg_jf);
+	value = ipa_agg_value_from_jfunc (caller_info, cs->caller,
+					  &agg_jf);
       if (value)
 	{
 	  struct ipa_argagg_value iav;
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index e2a86680a21..fd3d7d6c5e8 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -386,15 +386,6 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
       int j;
       struct expr_eval_op *op;
 
-      /* We allow call stmt to have fewer arguments than the callee function
-         (especially for K&R style programs).  So bound check here (we assume
-         m_known_aggs vector is either empty or has the same length as
-         m_known_vals).  */
-      gcc_checking_assert (!avals->m_known_aggs.length ()
-			   || !avals->m_known_vals.length ()
-			   || (avals->m_known_vals.length ()
-			       == avals->m_known_aggs.length ()));
-
       if (c->agg_contents)
 	{
 	  if (c->code == ipa_predicate::changed
@@ -402,14 +393,14 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
 	      && (avals->safe_sval_at(c->operand_num) == error_mark_node))
 	    continue;
 
-	  if (ipa_agg_value_set *agg = avals->safe_aggval_at (c->operand_num))
+	  if (tree sval = avals->safe_sval_at (c->operand_num))
+	    val = ipa_find_agg_cst_from_init (sval, c->offset, c->by_ref);
+	  if (!val)
 	    {
-	      tree sval = avals->safe_sval_at (c->operand_num);
-	      val = ipa_find_agg_cst_for_param (agg, sval, c->offset,
-						c->by_ref);
+	      ipa_argagg_value_list avs (avals);
+	      val = avs.get_value (c->operand_num, c->offset / BITS_PER_UNIT,
+				   c->by_ref);
 	    }
-	  else
-	    val = NULL_TREE;
 	}
       else
 	{
@@ -674,17 +665,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 
 		/* Determine known aggregate values.  */
 		if (fre_will_run_p (caller))
-		  {
-		    ipa_agg_value_set agg
-			= ipa_agg_value_set_from_jfunc (caller_parms_info,
-							caller, &jf->agg);
-		    if (agg.items.length ())
-		      {
-			if (!avals->m_known_aggs.length ())
-			  avals->m_known_aggs.safe_grow_cleared (count, true);
-			avals->m_known_aggs[i] = agg;
-		      }
-		  }
+		  ipa_push_agg_values_from_jfunc (caller_parms_info,
+						  caller, &jf->agg, i,
+						  &avals->m_known_aggs);
 	      }
 
 	    /* For calls used in polymorphic calls we further determine
@@ -3446,8 +3429,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size,
 	{
 	  if (ipa_is_param_used_by_indirect_call (params_summary, i)
 	      && (avals->safe_sval_at (i)
-		  || (avals->m_known_aggs.length () > i
-		      && avals->m_known_aggs[i].items.length ())))
+		  || (ipa_argagg_value_list (avals).value_for_index_p (i))))
 	    use_table = false;
 	  else if (ipa_is_param_used_by_polymorphic_call (params_summary, i)
 		   && (avals->m_known_contexts.length () > i
@@ -3583,14 +3565,12 @@ ipa_cached_call_context::duplicate_from (const ipa_call_context &ctx)
   m_avals.m_known_aggs = vNULL;
   if (ctx.m_avals.m_known_aggs.exists ())
     {
-      unsigned int n = MIN (ctx.m_avals.m_known_aggs.length (), nargs);
-
-      for (unsigned int i = 0; i < n; i++)
+      const ipa_argagg_value_list avl (&ctx.m_avals);
+      for (unsigned int i = 0; i < nargs; i++)
 	if (ipa_is_param_used_by_indirect_call (params_summary, i)
-	    && !ctx.m_avals.m_known_aggs[i].is_empty ())
+	    && avl.value_for_index_p (i))
 	  {
-	    m_avals.m_known_aggs
-	      = ipa_copy_agg_values (ctx.m_avals.m_known_aggs);
+	    m_avals.m_known_aggs = ctx.m_avals.m_known_aggs.copy ();
 	    break;
 	  }
     }
@@ -3607,7 +3587,7 @@ ipa_cached_call_context::release ()
   /* See if context is initialized at first place.  */
   if (!m_node)
     return;
-  ipa_release_agg_values (m_avals.m_known_aggs, true);
+  m_avals.m_known_aggs.release ();
   m_avals.m_known_vals.release ();
   m_avals.m_known_contexts.release ();
   m_inline_param_summary.release ();
@@ -3708,28 +3688,59 @@ ipa_call_context::equal_to (const ipa_call_context &ctx)
     }
   if (m_avals.m_known_aggs.exists () || ctx.m_avals.m_known_aggs.exists ())
     {
-      for (unsigned int i = 0; i < nargs; i++)
+      unsigned i = 0, j = 0;
+      while (i < m_avals.m_known_aggs.length ()
+	     || j < ctx.m_avals.m_known_aggs.length ())
 	{
-	  if (!ipa_is_param_used_by_indirect_call (params_summary, i))
-	    continue;
-	  if (i >= m_avals.m_known_aggs.length ()
-	      || m_avals.m_known_aggs[i].is_empty ())
+	  if (i >= m_avals.m_known_aggs.length ())
 	    {
-	      if (i < ctx.m_avals.m_known_aggs.length ()
-		  && !ctx.m_avals.m_known_aggs[i].is_empty ())
+	      int idx2 = ctx.m_avals.m_known_aggs[j].index;
+	      if (ipa_is_param_used_by_indirect_call (params_summary, idx2))
 		return false;
+	      j++;
 	      continue;
 	    }
-	  if (i >= ctx.m_avals.m_known_aggs.length ()
-	      || ctx.m_avals.m_known_aggs[i].is_empty ())
+	  if (j >= ctx.m_avals.m_known_aggs.length ())
 	    {
-	      if (i < m_avals.m_known_aggs.length ()
-		  && !m_avals.m_known_aggs[i].is_empty ())
+	      int idx1 = m_avals.m_known_aggs[i].index;
+	      if (ipa_is_param_used_by_indirect_call (params_summary, idx1))
 		return false;
+	      i++;
 	      continue;
 	    }
-	  if (!m_avals.m_known_aggs[i].equal_to (ctx.m_avals.m_known_aggs[i]))
+
+	  int idx1 = m_avals.m_known_aggs[i].index;
+	  int idx2 = ctx.m_avals.m_known_aggs[j].index;
+	  if (idx1 < idx2)
+	    {
+	      if (ipa_is_param_used_by_indirect_call (params_summary, idx1))
+		return false;
+	      i++;
+	      continue;
+	    }
+	  if (idx1 > idx2)
+	    {
+	      if (ipa_is_param_used_by_indirect_call (params_summary, idx2))
+		return false;
+	      j++;
+	      continue;
+	    }
+	  if (!ipa_is_param_used_by_indirect_call (params_summary, idx1))
+	    {
+	      i++;
+	      j++;
+	      continue;
+	    }
+
+	  if ((m_avals.m_known_aggs[i].unit_offset
+	       != ctx.m_avals.m_known_aggs[j].unit_offset)
+	      || (m_avals.m_known_aggs[i].by_ref
+	       != ctx.m_avals.m_known_aggs[j].by_ref)
+	      || !operand_equal_p (m_avals.m_known_aggs[i].value,
+				   ctx.m_avals.m_known_aggs[j].value))
 	    return false;
+	  i++;
+	  j++;
 	}
     }
   return true;
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 6196d7e6bdb..ee1acf85a95 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -3608,7 +3608,7 @@ find_constructor_constant_at_offset (tree constructor, HOST_WIDE_INT req_offset)
    invariant from a static constructor and if so, return it.  Otherwise return
    NULL. */
 
-static tree
+tree
 ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
 {
   if (by_ref)
@@ -3628,47 +3628,24 @@ ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
   return find_constructor_constant_at_offset (DECL_INITIAL (scalar), offset);
 }
 
-/* Retrieve value from AGG, a set of known offset/value for an aggregate or
-   static initializer of SCALAR (which can be NULL) for the given OFFSET or
-   return NULL if there is none.  BY_REF specifies whether the value has to be
-   passed by reference or by value.  If FROM_GLOBAL_CONSTANT is non-NULL, then
-   the boolean it points to is set to true if the value comes from an
-   initializer of a constant.  */
+/* Retrieve value from AGG_JFUNC for the given OFFSET or return NULL if there
+   is none.  BY_REF specifies whether the value has to be passed by reference
+   or by value.  */
 
-tree
-ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
-			    HOST_WIDE_INT offset, bool by_ref,
-			    bool *from_global_constant)
+static tree
+ipa_find_agg_cst_from_jfunc_items (struct ipa_agg_jump_function *agg_jfunc,
+				   ipa_node_params *src_info,
+				   cgraph_node *src_node,
+				   HOST_WIDE_INT offset, bool by_ref)
 {
-  struct ipa_agg_value *item;
-  int i;
+  if (by_ref != agg_jfunc->by_ref)
+    return NULL_TREE;
 
-  if (scalar)
-    {
-      tree res = ipa_find_agg_cst_from_init (scalar, offset, by_ref);
-      if (res)
-	{
-	  if (from_global_constant)
-	    *from_global_constant = true;
-	  return res;
-	}
-    }
+  for (const ipa_agg_jf_item &item : agg_jfunc->items)
+    if (item.offset == offset)
+      return ipa_agg_value_from_jfunc (src_info, src_node, &item);
 
-  if (!agg
-      || by_ref != agg->by_ref)
-    return NULL;
-
-  FOR_EACH_VEC_ELT (agg->items, i, item)
-    if (item->offset == offset)
-      {
-	/* Currently we do not have clobber values, return NULL for them once
-	   we do.  */
-	gcc_checking_assert (is_gimple_ip_invariant (item->value));
-	if (from_global_constant)
-	  *from_global_constant = false;
-	return item->value;
-      }
-  return NULL;
+  return NULL_TREE;
 }
 
 /* Remove a reference to SYMBOL from the list of references of a node given by
@@ -3765,24 +3742,19 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
 				  class ipa_node_params *new_root_info)
 {
   struct cgraph_edge *cs;
-  tree target;
+  tree target = NULL_TREE;
   bool agg_contents = ie->indirect_info->agg_contents;
   tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type);
   if (agg_contents)
     {
-      bool from_global_constant;
-      ipa_agg_value_set agg = ipa_agg_value_set_from_jfunc (new_root_info,
-							    new_root,
-							    &jfunc->agg);
-      target = ipa_find_agg_cst_for_param (&agg, scalar,
-					   ie->indirect_info->offset,
-					   ie->indirect_info->by_ref,
-					   &from_global_constant);
-      agg.release ();
-      if (target
-	  && !from_global_constant
-	  && !ie->indirect_info->guaranteed_unmodified)
-	return NULL;
+      if (scalar)
+	target = ipa_find_agg_cst_from_init (scalar, ie->indirect_info->offset,
+					     ie->indirect_info->by_ref);
+      if (!target && ie->indirect_info->guaranteed_unmodified)
+	target = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
+						    new_root,
+						    ie->indirect_info->offset,
+						    ie->indirect_info->by_ref);
     }
   else
     target = scalar;
@@ -3857,15 +3829,14 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
     {
       tree vtable;
       unsigned HOST_WIDE_INT offset;
-      tree scalar = (jfunc->type == IPA_JF_CONST) ? ipa_get_jf_constant (jfunc)
-	: NULL;
-      ipa_agg_value_set agg = ipa_agg_value_set_from_jfunc (new_root_info,
-							    new_root,
-							    &jfunc->agg);
-      tree t = ipa_find_agg_cst_for_param (&agg, scalar,
-					   ie->indirect_info->offset,
-					   true);
-      agg.release ();
+      tree t = NULL_TREE;
+      if (jfunc->type == IPA_JF_CONST)
+	t = ipa_find_agg_cst_from_init (ipa_get_jf_constant (jfunc),
+					ie->indirect_info->offset, true);
+      if (!t)
+	t = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
+					       new_root,
+					       ie->indirect_info->offset, true);
       if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
 	{
 	  bool can_refer;
@@ -6060,21 +6031,4 @@ ipcp_transform_function (struct cgraph_node *node)
 }
 
 
-/* Return true if OTHER describes same agg value.  */
-bool
-ipa_agg_value::equal_to (const ipa_agg_value &other)
-{
-  return offset == other.offset
-	 && operand_equal_p (value, other.value, 0);
-}
-
-/* Destructor also removing individual aggregate values.  */
-
-ipa_auto_call_arg_values::~ipa_auto_call_arg_values ()
-{
-  ipa_release_agg_values (m_known_aggs, false);
-}
-
-
-
 #include "gt-ipa-prop.h"
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index b04c1d1e8f9..1ff3cd48a6a 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -190,6 +190,8 @@ struct GTY(()) ipa_agg_jump_function
 };
 
 class ipcp_transformation;
+class ipa_auto_call_arg_values;
+class ipa_call_arg_values;
 
 /* Element of a vector describing aggregate values for a number of arguments in
    a particular context, be it a call or the aggregate constants that a node is
@@ -224,6 +226,8 @@ public:
   ipa_argagg_value_list (const vec<ipa_argagg_value> *values)
     : m_elts (*values)
   {}
+  ipa_argagg_value_list (const ipa_auto_call_arg_values *aavals);
+  ipa_argagg_value_list (const ipa_call_arg_values *gavals);
   ipa_argagg_value_list (const ipcp_transformation *tinfo);
 
   /* Return the aggregate constant stored for INDEX at UNIT_OFFSET, if it is
@@ -243,12 +247,22 @@ public:
 
   const ipa_argagg_value *get_elt (int index, unsigned unit_offset) const;
 
+
   /* Return the first item describing a constant stored for parameter with
      INDEX, regardless of offset or reference, or NULL if there is no such
      constant.  */
 
   const ipa_argagg_value *get_elt_for_index (int index) const;
 
+  /* Return true if there is an aggregate constant referring to a value passed
+     in or by parameter with INDEX (at any offset, whether by reference or
+     not).  */
+
+  bool value_for_index_p (int index) const
+  {
+    return !!get_elt_for_index (index);
+  }
+
   /* Return true if all elements present in OTHER are also present in this
      class.  */
 
@@ -275,105 +289,6 @@ public:
   array_slice<const ipa_argagg_value> m_elts;
 };
 
-/* An element in an aggregate part describing a known value at a given offset.
-   All unlisted positions are assumed to be unknown and all listed values must
-   fulfill is_gimple_ip_invariant.  */
-
-struct ipa_agg_value
-{
-  /* The offset at which the known value is located within the aggregate.  */
-  HOST_WIDE_INT offset;
-
-  /* The known constant.  */
-  tree value;
-
-  /* Return true if OTHER describes same agg value.  */
-  bool equal_to (const ipa_agg_value &other);
-};
-
-/* Structure describing a set of known offset/value for aggregate.  */
-
-struct ipa_agg_value_set
-{
-  /* Description of the individual item.  */
-  vec<ipa_agg_value> items;
-  /* True if the data was passed by reference (as opposed to by value).  */
-  bool by_ref;
-
-  /* Return true if OTHER describes same agg values.  */
-  bool equal_to (const ipa_agg_value_set &other)
-  {
-    if (by_ref != other.by_ref)
-      return false;
-    if (items.length () != other.items.length ())
-      return false;
-    for (unsigned int i = 0; i < items.length (); i++)
-      if (!items[i].equal_to (other.items[i]))
-	return false;
-    return true;
-  }
-
-  /* Return true if there is any value for aggregate.  */
-  bool is_empty () const
-  {
-    return items.is_empty ();
-  }
-
-  ipa_agg_value_set copy () const
-  {
-    ipa_agg_value_set new_copy;
-
-    new_copy.items = items.copy ();
-    new_copy.by_ref = by_ref;
-
-    return new_copy;
-  }
-
-  void release ()
-  {
-    items.release ();
-  }
-};
-
-/* Return copy of a vec<ipa_agg_value_set>.  */
-
-static inline vec<ipa_agg_value_set>
-ipa_copy_agg_values (const vec<ipa_agg_value_set> &aggs)
-{
-  vec<ipa_agg_value_set> aggs_copy = vNULL;
-
-  if (!aggs.is_empty ())
-    {
-      ipa_agg_value_set *agg;
-      int i;
-
-      aggs_copy.reserve_exact (aggs.length ());
-
-      FOR_EACH_VEC_ELT (aggs, i, agg)
-	aggs_copy.quick_push (agg->copy ());
-    }
-
-  return aggs_copy;
-}
-
-/* For vec<ipa_agg_value_set>, DO NOT call release(), use below function
-   instead.  Because ipa_agg_value_set contains a field of vector type, we
-   should release this child vector in each element before reclaiming the
-   whole vector.  */
-
-static inline void
-ipa_release_agg_values (vec<ipa_agg_value_set> &aggs,
-			bool release_vector = true)
-{
-  ipa_agg_value_set *agg;
-  int i;
-
-  FOR_EACH_VEC_ELT (aggs, i, agg)
-    agg->release ();
-  if (release_vector)
-    aggs.release ();
-}
-
 /* Information about zero/non-zero bits.  */
 class GTY(()) ipa_bits
 {
@@ -551,28 +466,15 @@ ipa_get_jf_ancestor_keep_null (struct ipa_jump_func *jfunc)
 class ipa_auto_call_arg_values
 {
 public:
-  ~ipa_auto_call_arg_values ();
-
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
      return its element at INDEX, otherwise return NULL.  */
   tree safe_sval_at (int index)
   {
-    /* TODO: Assert non-negative index here and test.  */
     if ((unsigned) index < m_known_vals.length ())
       return m_known_vals[index];
     return NULL;
   }
 
-  /* If m_known_aggs is sufficiantly long, return the pointer rto its element
-     at INDEX, otherwise return NULL.  */
-  ipa_agg_value_set *safe_aggval_at (int index)
-  {
-    /* TODO: Assert non-negative index here and test.  */
-    if ((unsigned) index < m_known_aggs.length ())
-      return &m_known_aggs[index];
-    return NULL;
-  }
-
   /* Vector describing known values of parameters.  */
   auto_vec<tree, 32> m_known_vals;
 
@@ -580,15 +482,22 @@ public:
   auto_vec<ipa_polymorphic_call_context, 32> m_known_contexts;
 
   /* Vector describing known aggregate values.  */
-  auto_vec<ipa_agg_value_set, 32> m_known_aggs;
+  auto_vec<ipa_argagg_value, 32> m_known_aggs;
 
   /* Vector describing known value ranges of arguments.  */
   auto_vec<value_range, 32> m_known_value_ranges;
 };
 
+inline
+ipa_argagg_value_list
+::ipa_argagg_value_list (const ipa_auto_call_arg_values *aavals)
+  : m_elts (aavals->m_known_aggs)
+{}
+
 /* Class bundling the various potentially known properties about actual
    arguments of a particular call.  This variant does not deallocate the
-   bundled data in any way.  */
+   bundled data in any way as the vectors can either be pointing to vectors in
+   ipa_auto_call_arg_values or be allocated independently.  */
 
 class ipa_call_arg_values
 {
@@ -613,22 +522,11 @@ public:
      return its element at INDEX, otherwise return NULL.  */
   tree safe_sval_at (int index)
   {
-    /* TODO: Assert non-negative index here and test.  */
     if ((unsigned) index < m_known_vals.length ())
       return m_known_vals[index];
     return NULL;
   }
 
-  /* If m_known_aggs is sufficiantly long, return the pointer rto its element
-     at INDEX, otherwise return NULL.  */
-  ipa_agg_value_set *safe_aggval_at (int index)
-  {
-    /* TODO: Assert non-negative index here and test.  */
-    if ((unsigned) index < m_known_aggs.length ())
-      return &m_known_aggs[index];
-    return NULL;
-  }
-
   /* Vector describing known values of parameters.  */
   vec<tree> m_known_vals = vNULL;
 
@@ -636,12 +534,17 @@ public:
   vec<ipa_polymorphic_call_context> m_known_contexts = vNULL;
 
   /* Vector describing known aggregate values.  */
-  vec<ipa_agg_value_set> m_known_aggs = vNULL;
+  vec<ipa_argagg_value> m_known_aggs = vNULL;
 
   /* Vector describing known value ranges of arguments.  */
   vec<value_range> m_known_value_ranges = vNULL;
 };
 
+inline
+ipa_argagg_value_list
+::ipa_argagg_value_list (const ipa_call_arg_values *gavals)
+  : m_elts (gavals->m_known_aggs)
+{}
 
 /* Summary describing a single formal parameter.  */
 
@@ -1190,9 +1093,6 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
 tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
 				   ipa_call_arg_values *avals,
 				   bool *speculative);
-tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
-				   ipa_auto_call_arg_values *avals,
-				   bool *speculative);
 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);
@@ -1204,9 +1104,8 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value,
 void ipa_analyze_node (struct cgraph_node *);
 
 /* Aggregate jump function related functions.  */
-tree ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
-				 HOST_WIDE_INT offset, bool by_ref,
-				 bool *from_global_constant = NULL);
+tree ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset,
+				 bool by_ref);
 bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
 			     vec<ipa_param_descriptor, va_gc> *descriptors,
 			     gimple *stmt, tree op, int *index_p,
@@ -1243,6 +1142,8 @@ void ipcp_read_transformation_summaries (void);
 int ipa_get_param_decl_index (class ipa_node_params *, tree);
 tree ipa_value_from_jfunc (class ipa_node_params *info,
 			   struct ipa_jump_func *jfunc, tree type);
+tree ipa_agg_value_from_jfunc (ipa_node_params *info, cgraph_node *node,
+			       const ipa_agg_jf_item *item);
 unsigned int ipcp_transform_function (struct cgraph_node *node);
 ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
 						     cgraph_edge *,
@@ -1250,9 +1151,10 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
 						     ipa_jump_func *);
 value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
 					ipa_jump_func *, tree);
-ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *,
-						cgraph_node *,
-						ipa_agg_jump_function *);
+void ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node,
+				     ipa_agg_jump_function *agg_jfunc,
+				     unsigned dst_index,
+				     vec<ipa_argagg_value> *res);
 void ipa_dump_param (FILE *, class ipa_node_params *info, int i);
 void ipa_release_body_info (struct ipa_func_body_info *);
 tree ipa_get_callee_param_type (struct cgraph_edge *e, int i);
-- 
2.37.2



More information about the Gcc-patches mailing list