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  <mjam...@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

Reply via email to