Feng,

this now looks fine to me: what is the current schedule to get this merged?

Thanks,
Philipp.

> On 19.09.2019, at 16:30, Feng Xue OS <fxue at os dot amperecomputing dot com> 
> wrote:
> 
> Fix a bug on unary/binary operation check.
> 
> Feng
> ---
> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
> index 33d52fe5537..f218f1093b8 100644
> --- a/gcc/ipa-cp.c
> +++ b/gcc/ipa-cp.c
> @@ -1244,23 +1244,23 @@ initialize_node_lattices (struct cgraph_node *node)
>       }
> }
> 
> -/* Return the result of a (possibly arithmetic) pass through jump function
> -   JFUNC on the constant value INPUT.  RES_TYPE is the type of the parameter
> -   to which the result is passed.  Return NULL_TREE if that cannot be
> -   determined or be considered an interprocedural invariant.  */
> +/* Return the result of a (possibly arithmetic) operation on the constant
> +   value INPUT.  OPERAND is 2nd operand for binary operation.  RES_TYPE is
> +   the type of the parameter to which the result is passed.  Return
> +   NULL_TREE if that cannot be determined or be considered an
> +   interprocedural invariant.  */
> 
> static tree
> -ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input,
> -                             tree res_type)
> +ipa_get_jf_arith_result (enum tree_code opcode, tree input, tree operand,
> +                      tree res_type)
> {
>   tree res;
> 
> -  if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
> +  if (opcode == NOP_EXPR)
>     return input;
>   if (!is_gimple_ip_invariant (input))
>     return NULL_TREE;
> 
> -  tree_code opcode = ipa_get_jf_pass_through_operation (jfunc);
>   if (!res_type)
>     {
>       if (TREE_CODE_CLASS (opcode) == tcc_comparison)
> @@ -1274,8 +1274,7 @@ ipa_get_jf_pass_through_result (struct ipa_jump_func 
> *jfunc, tree input,
>   if (TREE_CODE_CLASS (opcode) == tcc_unary)
>     res = fold_unary (opcode, res_type, input);
>   else
> -    res = fold_binary (opcode, res_type, input,
> -                    ipa_get_jf_pass_through_operand (jfunc));
> +    res = fold_binary (opcode, res_type, input, operand);
> 
>   if (res && !is_gimple_ip_invariant (res))
>     return NULL_TREE;
> @@ -1283,6 +1282,21 @@ ipa_get_jf_pass_through_result (struct ipa_jump_func 
> *jfunc, tree input,
>   return res;
> }
> 
> +/* Return the result of a (possibly arithmetic) pass through jump function
> +   JFUNC on the constant value INPUT.  RES_TYPE is the type of the parameter
> +   to which the result is passed.  Return NULL_TREE if that cannot be
> +   determined or be considered an interprocedural invariant.  */
> +
> +static tree
> +ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input,
> +                             tree res_type)
> +{
> +  return ipa_get_jf_arith_result (ipa_get_jf_pass_through_operation (jfunc),
> +                               input,
> +                               ipa_get_jf_pass_through_operand (jfunc),
> +                               res_type);
> +}
> +
> /* Return the result of an ancestor jump function JFUNC on the constant value
>    INPUT.  Return NULL_TREE if that cannot be determined.  */
> 
> @@ -1416,6 +1430,146 @@ ipa_context_from_jfunc (ipa_node_params *info, 
> cgraph_edge *cs, int csidx,
>   return ctx;
> }
> 
> +/* See if NODE is a clone with a known aggregate value at a given OFFSET of a
> +   parameter with the given INDEX.  */
> +
> +static tree
> +get_clone_agg_value (struct cgraph_node *node, HOST_WIDE_INT offset,
> +                  int index)
> +{
> +  struct ipa_agg_replacement_value *aggval;
> +
> +  aggval = ipa_get_agg_replacements_for_node (node);
> +  while (aggval)
> +    {
> +      if (aggval->offset == offset
> +       && aggval->index == index)
> +     return aggval->value;
> +      aggval = aggval->next;
> +    }
> +  return NULL_TREE;
> +}
> +
> +/* Determine whether ITEM, jump function for an aggregate part, evaluates to 
> a
> +   single known constant value and if so, return it.  Otherwise return NULL.
> +   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,
> +                      struct ipa_agg_jf_item *item)
> +{
> +  tree value = NULL_TREE;
> +  int src_idx;
> +
> +  if (item->offset < 0 || item->jftype == IPA_JF_UNKNOWN)
> +    return NULL_TREE;
> +
> +  if (item->jftype == IPA_JF_CONST)
> +    return item->value.constant;
> +
> +  gcc_checking_assert (item->jftype == IPA_JF_PASS_THROUGH
> +                    || item->jftype == IPA_JF_LOAD_AGG);
> +
> +  src_idx = item->value.pass_through.formal_id;
> +
> +  if (info->ipcp_orig_node)
> +    {
> +      if (item->jftype == IPA_JF_PASS_THROUGH)
> +     value = info->known_csts[src_idx];
> +      else
> +     value = get_clone_agg_value (node, item->value.load_agg.offset,
> +                                  src_idx);
> +    }
> +  else if (info->lattices)
> +    {
> +      class ipcp_param_lattices *src_plats
> +             = ipa_get_parm_lattices (info, src_idx);
> +
> +      if (item->jftype == IPA_JF_PASS_THROUGH)
> +     {
> +       struct ipcp_lattice<tree> *lat = &src_plats->itself;
> +
> +       if (!lat->is_single_const ())
> +         return NULL_TREE;
> +
> +       value = lat->values->value;
> +     }
> +      else if (src_plats->aggs
> +            && !src_plats->aggs_bottom
> +            && !src_plats->aggs_contain_variable
> +            && src_plats->aggs_by_ref == item->value.load_agg.by_ref)
> +     {
> +       struct ipcp_agg_lattice *aglat;
> +
> +       for (aglat = src_plats->aggs; aglat; aglat = aglat->next)
> +         {
> +           if (aglat->offset > item->value.load_agg.offset)
> +             break;
> +
> +           if (aglat->offset == item->value.load_agg.offset)
> +             {
> +               if (aglat->is_single_const ())
> +                 value = aglat->values->value;
> +               break;
> +             }
> +         }
> +     }
> +    }
> +
> +  if (!value)
> +    return NULL_TREE;
> +
> +  if (item->jftype == IPA_JF_LOAD_AGG)
> +    {
> +      tree load_type = item->value.load_agg.type;
> +      tree value_type = TREE_TYPE (value);
> +
> +      /* Ensure value type is compatible with load type.  */
> +      if (!useless_type_conversion_p (load_type, value_type))
> +     return NULL_TREE;
> +    }
> +
> +  return ipa_get_jf_arith_result (item->value.pass_through.operation,
> +                               value,
> +                               item->value.pass_through.operand,
> +                               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.  */
> +
> +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)
> +{
> +  struct ipa_agg_value_set agg;
> +  struct ipa_agg_jf_item *item;
> +  int i;
> +
> +  agg.items = vNULL;
> +  agg.by_ref = agg_jfunc->by_ref;
> +
> +  FOR_EACH_VEC_SAFE_ELT (agg_jfunc->items, i, item)
> +    {
> +      tree value = ipa_agg_value_from_node (info, node, item);
> +
> +      if (value)
> +     {
> +       struct ipa_agg_value value_item;
> +
> +       value_item.offset = item->offset;
> +       value_item.value = value;
> +
> +       agg.items.safe_push (value_item);
> +     }
> +    }
> +  return agg;
> +}
> +
> /* If checking is enabled, verify that no lattice is in the TOP state, i.e. 
> not
>    bottom, not containing a variable component and without any known value at
>    the same time.  */
> @@ -1592,16 +1746,25 @@ ipcp_lattice<valtype>::add_value (valtype newval, 
> cgraph_edge *cs,
>   return true;
> }
> 
> -/* Propagate values through a pass-through jump function JFUNC associated 
> with
> -   edge CS, taking values from SRC_LAT and putting them into DEST_LAT.  
> SRC_IDX
> -   is the index of the source parameter.  PARM_TYPE is the type of the
> -   parameter to which the result is passed.  */
> +/* Propagate values through an arithmetic transformation described by a jump
> +   function associated with edge CS, taking values from SRC_LAT and putting
> +   them into DEST_LAT.  OPND1_TYPE is expected type for the values in 
> SRC_LAT.
> +   OPND2 is a constant value if transformation is a binary operation.
> +   SRC_OFFSET specifies offset in an aggregate if SRC_LAT describes lattice 
> of
> +   a part of the aggregate.  SRC_IDX is the index of the source parameter.
> +   RES_TYPE is the value type of result being propagated into.  Return true 
> if
> +   DEST_LAT changed.  */
> 
> static bool
> -propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc,
> -                                 ipcp_lattice<tree> *src_lat,
> -                                 ipcp_lattice<tree> *dest_lat, int src_idx,
> -                                 tree parm_type)
> +propagate_vals_across_arith_jfunc (cgraph_edge *cs,
> +                                enum tree_code opcode,
> +                                tree opnd1_type,
> +                                tree opnd2,
> +                                ipcp_lattice<tree> *src_lat,
> +                                ipcp_lattice<tree> *dest_lat,
> +                                HOST_WIDE_INT src_offset,
> +                                int src_idx,
> +                                tree res_type)
> {
>   ipcp_value<tree> *src_val;
>   bool ret = false;
> @@ -1611,17 +1774,22 @@ propagate_vals_across_pass_through (cgraph_edge *cs, 
> ipa_jump_func *jfunc,
>      number of them and we would just make lattices bottom.  If this condition
>      is ever relaxed we have to detect self-feeding recursive calls in
>      cgraph_edge_brings_value_p in a smarter way.  */
> -  if ((ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR)
> -      && ipa_edge_within_scc (cs))
> +  if (opcode != NOP_EXPR && ipa_edge_within_scc (cs))
>     ret = dest_lat->set_contains_variable ();
>   else
>     for (src_val = src_lat->values; src_val; src_val = src_val->next)
>       {
> -     tree cstval = ipa_get_jf_pass_through_result (jfunc, src_val->value,
> -                                                   parm_type);
> +     tree opnd1 = src_val->value;
> +     tree cstval = NULL_TREE;
> +
> +     /* Skip source values that is incompatible with specified type.  */
> +     if (!opnd1_type
> +         || useless_type_conversion_p (opnd1_type, TREE_TYPE (opnd1)))
> +       cstval = ipa_get_jf_arith_result (opcode, opnd1, opnd2, res_type);
> 
>       if (cstval)
> -       ret |= dest_lat->add_value (cstval, cs, src_val, src_idx);
> +       ret |= dest_lat->add_value (cstval, cs, src_val, src_idx,
> +                                   src_offset);
>       else
>         ret |= dest_lat->set_contains_variable ();
>       }
> @@ -1629,6 +1797,24 @@ propagate_vals_across_pass_through (cgraph_edge *cs, 
> ipa_jump_func *jfunc,
>   return ret;
> }
> 
> +/* Propagate values through a pass-through jump function JFUNC associated 
> with
> +   edge CS, taking values from SRC_LAT and putting them into DEST_LAT.  
> SRC_IDX
> +   is the index of the source parameter.  PARM_TYPE is the type of the
> +   parameter to which the result is passed.  */
> +
> +static bool
> +propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc,
> +                                 ipcp_lattice<tree> *src_lat,
> +                                 ipcp_lattice<tree> *dest_lat, int src_idx,
> +                                 tree parm_type)
> +{
> +  return propagate_vals_across_arith_jfunc (cs,
> +                             ipa_get_jf_pass_through_operation (jfunc),
> +                             NULL_TREE,
> +                             ipa_get_jf_pass_through_operand (jfunc),
> +                             src_lat, dest_lat, -1, src_idx, parm_type);
> +}
> +
> /* Propagate values through an ancestor jump function JFUNC associated with
>    edge CS, taking values from SRC_LAT and putting them into DEST_LAT.  
> SRC_IDX
>    is the index of the source parameter.  */
> @@ -1789,7 +1975,6 @@ propagate_context_across_jump_function (cgraph_edge *cs,
>             added_sth = true;
>           }
>       }
> -
>     }
> 
>  prop_fail:
> @@ -2145,6 +2330,85 @@ agg_pass_through_permissible_p (class 
> ipcp_param_lattices *src_plats,
>       || ipa_get_jf_pass_through_agg_preserved (jfunc));
> }
> 
> +/* Propagate values through ITEM, jump function for a part of an aggregate,
> +   into corresponding aggregate lattice AGLAT.  CS is the call graph edge
> +   associated with the jump function.  Return true if AGLAT changed in any
> +   way.  */
> +
> +static bool
> +propagate_aggregate_lattice (struct cgraph_edge *cs,
> +                          struct ipa_agg_jf_item *item,
> +                          struct ipcp_agg_lattice *aglat)
> +{
> +  class ipa_node_params *caller_info;
> +  class ipcp_param_lattices *src_plats;
> +  struct ipcp_lattice<tree> *src_lat;
> +  HOST_WIDE_INT src_offset;
> +  int src_idx;
> +  tree load_type;
> +  bool ret;
> +
> +  if (item->jftype == IPA_JF_CONST)
> +    {
> +      tree value = item->value.constant;
> +
> +      gcc_checking_assert (is_gimple_ip_invariant (value));
> +      return aglat->add_value (value, cs, NULL, 0);
> +    }
> +
> +  gcc_checking_assert (item->jftype == IPA_JF_PASS_THROUGH
> +                    || item->jftype == IPA_JF_LOAD_AGG);
> +
> +  caller_info = IPA_NODE_REF (cs->caller);
> +  src_idx = item->value.pass_through.formal_id;
> +  src_plats = ipa_get_parm_lattices (caller_info, src_idx);
> +
> +  if (item->jftype == IPA_JF_PASS_THROUGH)
> +    {
> +      load_type = NULL_TREE;
> +      src_lat = &src_plats->itself;
> +      src_offset = -1;
> +    }
> +  else
> +    {
> +      HOST_WIDE_INT load_offset = item->value.load_agg.offset;
> +      struct ipcp_agg_lattice *src_aglat;
> +
> +      for (src_aglat = src_plats->aggs; src_aglat; src_aglat = 
> src_aglat->next)
> +     if (src_aglat->offset >= load_offset)
> +       break;
> +
> +      load_type = item->value.load_agg.type;
> +      if (!src_aglat
> +       || src_aglat->offset > load_offset
> +       || src_aglat->size != tree_to_shwi (TYPE_SIZE (load_type))
> +       || src_plats->aggs_by_ref != item->value.load_agg.by_ref)
> +     return aglat->set_contains_variable ();
> +
> +      src_lat = src_aglat;
> +      src_offset = load_offset;
> +    }
> +
> +  if (src_lat->bottom
> +      || (!ipcp_versionable_function_p (cs->caller)
> +       && !src_lat->is_single_const ()))
> +    return aglat->set_contains_variable ();
> +
> +  ret = propagate_vals_across_arith_jfunc (cs,
> +                                        item->value.pass_through.operation,
> +                                        load_type,
> +                                        item->value.pass_through.operand,
> +                                        src_lat, aglat,
> +                                        src_offset,
> +                                        src_idx,
> +                                        item->type);
> +
> +  if (src_lat->contains_variable)
> +    ret |= aglat->set_contains_variable ();
> +
> +  return ret;
> +}
> +
> /* Propagate scalar values across jump function JFUNC that is associated with
>    edge CS and put the values into DEST_LAT.  */
> 
> @@ -2212,15 +2476,14 @@ propagate_aggs_across_jump_function (struct 
> cgraph_edge *cs,
>       {
>         HOST_WIDE_INT val_size;
> 
> -       if (item->offset < 0)
> +       if (item->offset < 0 || item->jftype == IPA_JF_UNKNOWN)
>           continue;
> -       gcc_checking_assert (is_gimple_ip_invariant (item->value));
> -       val_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (item->value)));
> +       val_size = tree_to_shwi (TYPE_SIZE (item->type));
> 
>         if (merge_agg_lats_step (dest_plats, item->offset, val_size,
>                                  &aglat, pre_existing, &ret))
>           {
> -           ret |= (*aglat)->add_value (item->value, cs, NULL, 0, 0);
> +           ret |= propagate_aggregate_lattice (cs, item, *aglat);
>             aglat = &(*aglat)->next;
>           }
>         else if (dest_plats->aggs_bottom)
> @@ -2326,7 +2589,7 @@ static tree
> ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
>                               vec<tree> known_csts,
>                               vec<ipa_polymorphic_call_context> 
> known_contexts,
> -                             vec<ipa_agg_jump_function_p> known_aggs,
> +                             vec<ipa_agg_value_set> known_aggs,
>                               struct ipa_agg_replacement_value *agg_reps,
>                               bool *speculative)
> {
> @@ -2364,9 +2627,9 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
>           }
>         if (!t)
>           {
> -           struct ipa_agg_jump_function *agg;
> +           struct ipa_agg_value_set *agg;
>             if (known_aggs.length () > (unsigned int) param_index)
> -             agg = known_aggs[param_index];
> +             agg = &known_aggs[param_index];
>             else
>               agg = NULL;
>             bool from_global_constant;
> @@ -2420,8 +2683,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
>   if (!t && known_aggs.length () > (unsigned int) param_index
>       && !ie->indirect_info->by_ref)
>     {
> -      struct ipa_agg_jump_function *agg;
> -      agg = known_aggs[param_index];
> +      struct ipa_agg_value_set *agg = &known_aggs[param_index];
>       t = ipa_find_agg_cst_for_param (agg, known_csts[param_index],
>                                     ie->indirect_info->offset, true);
>     }
> @@ -2543,7 +2805,7 @@ tree
> ipa_get_indirect_edge_target (struct cgraph_edge *ie,
>                             vec<tree> known_csts,
>                             vec<ipa_polymorphic_call_context> known_contexts,
> -                           vec<ipa_agg_jump_function_p> known_aggs,
> +                           vec<ipa_agg_value_set> known_aggs,
>                             bool *speculative)
> {
>   return ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
> @@ -2557,7 +2819,7 @@ static int
> devirtualization_time_bonus (struct cgraph_node *node,
>                            vec<tree> known_csts,
>                            vec<ipa_polymorphic_call_context> known_contexts,
> -                          vec<ipa_agg_jump_function_p> known_aggs)
> +                          vec<ipa_agg_value_set> known_aggs)
> {
>   struct cgraph_edge *ie;
>   int res = 0;
> @@ -2691,25 +2953,25 @@ good_cloning_opportunity_p (struct cgraph_node *node, 
> int 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_jf_item, va_gc> *
> +static vec<ipa_agg_value>
> context_independent_aggregate_values (class ipcp_param_lattices *plats)
> {
> -  vec<ipa_agg_jf_item, va_gc> *res = NULL;
> +  vec<ipa_agg_value> res = vNULL;
> 
>   if (plats->aggs_bottom
>       || plats->aggs_contain_variable
>       || plats->aggs_count == 0)
> -    return NULL;
> +    return vNULL;
> 
>   for (struct ipcp_agg_lattice *aglat = plats->aggs;
>        aglat;
>        aglat = aglat->next)
>     if (aglat->is_single_const ())
>       {
> -     struct ipa_agg_jf_item item;
> +     struct ipa_agg_value item;
>       item.offset = aglat->offset;
>       item.value = aglat->values->value;
> -     vec_safe_push (res, item);
> +     res.safe_push (item);
>       }
>   return res;
> }
> @@ -2725,7 +2987,7 @@ gather_context_independent_values (class 
> ipa_node_params *info,
>                                  vec<tree> *known_csts,
>                                  vec<ipa_polymorphic_call_context>
>                                  *known_contexts,
> -                                vec<ipa_agg_jump_function> *known_aggs,
> +                                vec<ipa_agg_value_set> *known_aggs,
>                                  int *removable_params_cost)
> {
>   int i, count = ipa_get_param_count (info);
> @@ -2775,40 +3037,20 @@ gather_context_independent_values (class 
> ipa_node_params *info,
> 
>       if (known_aggs)
>       {
> -       vec<ipa_agg_jf_item, va_gc> *agg_items;
> -       struct ipa_agg_jump_function *ajf;
> +       vec<ipa_agg_value> agg_items;
> +       struct ipa_agg_value_set *agg;
> 
>         agg_items = context_independent_aggregate_values (plats);
> -       ajf = &(*known_aggs)[i];
> -       ajf->items = agg_items;
> -       ajf->by_ref = plats->aggs_by_ref;
> -       ret |= agg_items != NULL;
> +       agg = &(*known_aggs)[i];
> +       agg->items = agg_items;
> +       agg->by_ref = plats->aggs_by_ref;
> +       ret |= !agg_items.is_empty ();
>       }
>     }
> 
>   return ret;
> }
> 
> -/* The current interface in ipa-inline-analysis requires a pointer vector.
> -   Create it.
> -
> -   FIXME: That interface should be re-worked, this is slightly silly.  Still,
> -   I'd like to discuss how to change it first and this demonstrates the
> -   issue.  */
> -
> -static vec<ipa_agg_jump_function_p>
> -agg_jmp_p_vec_for_t_vec (vec<ipa_agg_jump_function> known_aggs)
> -{
> -  vec<ipa_agg_jump_function_p> ret;
> -  struct ipa_agg_jump_function *ajf;
> -  int i;
> -
> -  ret.create (known_aggs.length ());
> -  FOR_EACH_VEC_ELT (known_aggs, i, ajf)
> -    ret.quick_push (ajf);
> -  return ret;
> -}
> -
> /* Perform time and size measurement of NODE with the context given in
>    KNOWN_CSTS, KNOWN_CONTEXTS and KNOWN_AGGS, calculate the benefit and cost
>    given BASE_TIME of the node without specialization, REMOVABLE_PARAMS_COST 
> of
> @@ -2818,7 +3060,7 @@ agg_jmp_p_vec_for_t_vec (vec<ipa_agg_jump_function> 
> known_aggs)
> static void
> perform_estimation_of_a_value (cgraph_node *node, vec<tree> known_csts,
>                              vec<ipa_polymorphic_call_context> known_contexts,
> -                            vec<ipa_agg_jump_function_p> known_aggs_ptrs,
> +                            vec<ipa_agg_value_set> known_aggs,
>                              int removable_params_cost,
>                              int est_move_cost, ipcp_value_base *val)
> {
> @@ -2827,7 +3069,7 @@ perform_estimation_of_a_value (cgraph_node *node, 
> vec<tree> known_csts,
>   ipa_hints hints;
> 
>   estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
> -                                  known_aggs_ptrs, &size, &time,
> +                                  known_aggs, &size, &time,
>                                    &base_time, &hints);
>   base_time -= time;
>   if (base_time > 65535)
> @@ -2841,7 +3083,7 @@ perform_estimation_of_a_value (cgraph_node *node, 
> vec<tree> known_csts,
>   else
>     time_benefit = base_time.to_int ()
>       + devirtualization_time_bonus (node, known_csts, known_contexts,
> -                                  known_aggs_ptrs)
> +                                  known_aggs)
>       + hint_time_bonus (hints)
>       + removable_params_cost + est_move_cost;
> 
> @@ -2867,8 +3109,7 @@ estimate_local_effects (struct cgraph_node *node)
>   int i, count = ipa_get_param_count (info);
>   vec<tree> known_csts;
>   vec<ipa_polymorphic_call_context> known_contexts;
> -  vec<ipa_agg_jump_function> known_aggs;
> -  vec<ipa_agg_jump_function_p> known_aggs_ptrs;
> +  vec<ipa_agg_value_set> known_aggs;
>   bool always_const;
>   int removable_params_cost;
> 
> @@ -2881,9 +3122,8 @@ estimate_local_effects (struct cgraph_node *node)
>   always_const = gather_context_independent_values (info, &known_csts,
>                                                   &known_contexts, 
> &known_aggs,
>                                                   &removable_params_cost);
> -  known_aggs_ptrs = agg_jmp_p_vec_for_t_vec (known_aggs);
>   int devirt_bonus = devirtualization_time_bonus (node, known_csts,
> -                                        known_contexts, known_aggs_ptrs);
> +                                        known_contexts, known_aggs);
>   if (always_const || devirt_bonus
>       || (removable_params_cost && node->local.can_change_signature))
>     {
> @@ -2896,7 +3136,7 @@ estimate_local_effects (struct cgraph_node *node)
>       node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats,
>                                             false);
>       estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
> -                                      known_aggs_ptrs, &size, &time,
> +                                      known_aggs, &size, &time,
>                                        &base_time, &hints);
>       time -= devirt_bonus;
>       time -= hint_time_bonus (hints);
> @@ -2959,7 +3199,7 @@ estimate_local_effects (struct cgraph_node *node)
> 
>         int emc = estimate_move_cost (TREE_TYPE (val->value), true);
>         perform_estimation_of_a_value (node, known_csts, known_contexts,
> -                                      known_aggs_ptrs,
> +                                      known_aggs,
>                                        removable_params_cost, emc, val);
> 
>         if (dump_file && (dump_flags & TDF_DETAILS))
> @@ -2994,7 +3234,7 @@ estimate_local_effects (struct cgraph_node *node)
>       {
>         known_contexts[i] = val->value;
>         perform_estimation_of_a_value (node, known_csts, known_contexts,
> -                                      known_aggs_ptrs,
> +                                      known_aggs,
>                                        removable_params_cost, 0, val);
> 
>         if (dump_file && (dump_flags & TDF_DETAILS))
> @@ -3013,13 +3253,13 @@ estimate_local_effects (struct cgraph_node *node)
>   for (i = 0; i < count; i++)
>     {
>       class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
> -      struct ipa_agg_jump_function *ajf;
> +      struct ipa_agg_value_set *agg;
>       struct ipcp_agg_lattice *aglat;
> 
>       if (plats->aggs_bottom || !plats->aggs)
>       continue;
> 
> -      ajf = &known_aggs[i];
> +      agg = &known_aggs[i];
>       for (aglat = plats->aggs; aglat; aglat = aglat->next)
>       {
>         ipcp_value<tree> *val;
> @@ -3031,14 +3271,14 @@ estimate_local_effects (struct cgraph_node *node)
> 
>         for (val = aglat->values; val; val = val->next)
>           {
> -           struct ipa_agg_jf_item item;
> +           struct ipa_agg_value item;
> 
>             item.offset = aglat->offset;
>             item.value = val->value;
> -           vec_safe_push (ajf->items, item);
> +           agg->items.safe_push (item);
> 
>             perform_estimation_of_a_value (node, known_csts, known_contexts,
> -                                          known_aggs_ptrs,
> +                                          known_aggs,
>                                            removable_params_cost, 0, val);
> 
>             if (dump_file && (dump_flags & TDF_DETAILS))
> @@ -3054,18 +3294,14 @@ estimate_local_effects (struct cgraph_node *node)
>                          val->local_time_benefit, val->local_size_cost);
>               }
> 
> -           ajf->items->pop ();
> +           agg->items.pop ();
>           }
>       }
>     }
> 
> -  for (i = 0; i < count; i++)
> -    vec_free (known_aggs[i].items);
> -
>   known_csts.release ();
>   known_contexts.release ();
> -  known_aggs.release ();
> -  known_aggs_ptrs.release ();
> +  ipa_release_agg_values (known_aggs);
> }
> 
> 
> @@ -3433,26 +3669,6 @@ edge_clone_summary_t::duplicate (cgraph_edge 
> *src_edge, cgraph_edge *dst_edge,
>   src_data->next_clone = dst_edge;
> }
> 
> -/* See if NODE is a clone with a known aggregate value at a given OFFSET of a
> -   parameter with the given INDEX.  */
> -
> -static tree
> -get_clone_agg_value (struct cgraph_node *node, HOST_WIDE_INT offset,
> -                  int index)
> -{
> -  struct ipa_agg_replacement_value *aggval;
> -
> -  aggval = ipa_get_agg_replacements_for_node (node);
> -  while (aggval)
> -    {
> -      if (aggval->offset == offset
> -       && aggval->index == index)
> -     return aggval->value;
> -      aggval = aggval->next;
> -    }
> -  return NULL_TREE;
> -}
> -
> /* Return true is NODE is DEST or its clone for all contexts.  */
> 
> static bool
> @@ -4074,10 +4290,10 @@ find_more_contexts_for_caller_subset (cgraph_node 
> *node,
> /* Go through PLATS and create a vector of values consisting of values and
>    offsets (minus OFFSET) of lattices that contain only a single value.  */
> 
> -static vec<ipa_agg_jf_item>
> +static vec<ipa_agg_value>
> copy_plats_to_inter (class ipcp_param_lattices *plats, HOST_WIDE_INT offset)
> {
> -  vec<ipa_agg_jf_item> res = vNULL;
> +  vec<ipa_agg_value> res = vNULL;
> 
>   if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
>     return vNULL;
> @@ -4085,7 +4301,7 @@ copy_plats_to_inter (class ipcp_param_lattices *plats, 
> HOST_WIDE_INT offset)
>   for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = 
> aglat->next)
>     if (aglat->is_single_const ())
>       {
> -     struct ipa_agg_jf_item ti;
> +     struct ipa_agg_value ti;
>       ti.offset = aglat->offset - offset;
>       ti.value = aglat->values->value;
>       res.safe_push (ti);
> @@ -4098,11 +4314,11 @@ copy_plats_to_inter (class ipcp_param_lattices 
> *plats, HOST_WIDE_INT offset)
> 
> static void
> intersect_with_plats (class ipcp_param_lattices *plats,
> -                   vec<ipa_agg_jf_item> *inter,
> +                   vec<ipa_agg_value> *inter,
>                     HOST_WIDE_INT offset)
> {
>   struct ipcp_agg_lattice *aglat;
> -  struct ipa_agg_jf_item *item;
> +  struct ipa_agg_value *item;
>   int k;
> 
>   if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
> @@ -4140,18 +4356,18 @@ intersect_with_plats (class ipcp_param_lattices 
> *plats,
> /* Copy aggregate replacement values of NODE (which is an IPA-CP clone) to the
>    vector result while subtracting OFFSET from the individual value offsets.  
> */
> 
> -static vec<ipa_agg_jf_item>
> +static vec<ipa_agg_value>
> agg_replacements_to_vector (struct cgraph_node *node, int index,
>                           HOST_WIDE_INT offset)
> {
>   struct ipa_agg_replacement_value *av;
> -  vec<ipa_agg_jf_item> res = vNULL;
> +  vec<ipa_agg_value> res = vNULL;
> 
>   for (av = ipa_get_agg_replacements_for_node (node); av; av = av->next)
>     if (av->index == index
>       && (av->offset - offset) >= 0)
>     {
> -      struct ipa_agg_jf_item item;
> +      struct ipa_agg_value item;
>       gcc_checking_assert (av->value);
>       item.offset = av->offset - offset;
>       item.value = av->value;
> @@ -4167,11 +4383,11 @@ agg_replacements_to_vector (struct cgraph_node *node, 
> int index,
> 
> static void
> intersect_with_agg_replacements (struct cgraph_node *node, int index,
> -                              vec<ipa_agg_jf_item> *inter,
> +                              vec<ipa_agg_value> *inter,
>                                HOST_WIDE_INT offset)
> {
>   struct ipa_agg_replacement_value *srcvals;
> -  struct ipa_agg_jf_item *item;
> +  struct ipa_agg_value *item;
>   int i;
> 
>   srcvals = ipa_get_agg_replacements_for_node (node);
> @@ -4208,9 +4424,9 @@ intersect_with_agg_replacements (struct cgraph_node 
> *node, int index,
>    copy all incoming values to it.  If we determine we ended up with no values
>    whatsoever, return a released vector.  */
> 
> -static vec<ipa_agg_jf_item>
> +static vec<ipa_agg_value>
> intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
> -                             vec<ipa_agg_jf_item> inter)
> +                             vec<ipa_agg_value> inter)
> {
>   struct ipa_jump_func *jfunc;
>   jfunc = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), index);
> @@ -4291,12 +4507,26 @@ intersect_aggregates_with_edge (struct cgraph_edge 
> *cs, int index,
>     }
>   else if (jfunc->agg.items)
>     {
> -      struct ipa_agg_jf_item *item;
> +      class ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
> +      struct ipa_agg_value *item;
>       int k;
> 
>       if (!inter.exists ())
>       for (unsigned i = 0; i < jfunc->agg.items->length (); i++)
> -       inter.safe_push ((*jfunc->agg.items)[i]);
> +       {
> +         struct ipa_agg_jf_item *agg_item = &(*jfunc->agg.items)[i];
> +         tree value = ipa_agg_value_from_node (caller_info, cs->caller,
> +                                               agg_item);
> +         if (value)
> +           {
> +             struct ipa_agg_value agg_value;
> +
> +             agg_value.offset = agg_item->offset;
> +             agg_value.value = value;
> +
> +             inter.safe_push (agg_value);
> +           }
> +       }
>       else
>       FOR_EACH_VEC_ELT (inter, k, item)
>         {
> @@ -4314,9 +4544,10 @@ intersect_aggregates_with_edge (struct cgraph_edge 
> *cs, int index,
>                 break;
>               if (ti->offset == item->offset)
>                 {
> -                 gcc_checking_assert (ti->value);
> -                 if (values_equal_for_ipcp_p (item->value,
> -                                              ti->value))
> +                 tree value = ipa_agg_value_from_node (caller_info,
> +                                                       cs->caller, ti);
> +                 if (value
> +                     && values_equal_for_ipcp_p (item->value, value))
>                     found = true;
>                   break;
>                 }
> @@ -4329,7 +4560,7 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, 
> int index,
>   else
>     {
>       inter.release ();
> -      return vec<ipa_agg_jf_item>();
> +      return vNULL;
>     }
>   return inter;
> }
> @@ -4357,8 +4588,8 @@ find_aggregate_values_for_callers_subset (struct 
> cgraph_node *node,
>   for (i = 0; i < count; i++)
>     {
>       struct cgraph_edge *cs;
> -      vec<ipa_agg_jf_item> inter = vNULL;
> -      struct ipa_agg_jf_item *item;
> +      vec<ipa_agg_value> inter = vNULL;
> +      struct ipa_agg_value *item;
>       class ipcp_param_lattices *plats = ipa_get_parm_lattices (dest_info, i);
>       int j;
> 
> @@ -4465,7 +4696,7 @@ cgraph_edge_brings_all_agg_vals_for_node (struct 
> cgraph_edge *cs,
> 
>   for (i = 0; i < count; i++)
>     {
> -      static vec<ipa_agg_jf_item> values = vec<ipa_agg_jf_item>();
> +      static vec<ipa_agg_value> values = vNULL;
>       class ipcp_param_lattices *plats;
>       bool interesting = false;
>       for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
> @@ -4488,7 +4719,7 @@ cgraph_edge_brings_all_agg_vals_for_node (struct 
> cgraph_edge *cs,
>       for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
>       if (aggval->index == i)
>         {
> -         struct ipa_agg_jf_item *item;
> +         struct ipa_agg_value *item;
>           int j;
>           bool found = false;
>           FOR_EACH_VEC_ELT (values, j, item)
> @@ -4726,7 +4957,6 @@ decide_whether_version_node (struct cgraph_node *node)
>   int i, count = ipa_get_param_count (info);
>   vec<tree> known_csts;
>   vec<ipa_polymorphic_call_context> known_contexts;
> -  vec<ipa_agg_jump_function> known_aggs = vNULL;
>   bool ret = false;
> 
>   if (count == 0)
> @@ -4737,8 +4967,7 @@ decide_whether_version_node (struct cgraph_node *node)
>            node->dump_name ());
> 
>   gather_context_independent_values (info, &known_csts, &known_contexts,
> -                               info->do_clone_for_all_contexts ? &known_aggs
> -                               : NULL, NULL);
> +                                  NULL, NULL);
> 
>   for (i = 0; i < count;i++)
>     {
> @@ -4807,9 +5036,6 @@ decide_whether_version_node (struct cgraph_node *node)
>       info = IPA_NODE_REF (node);
>       info->do_clone_for_all_contexts = false;
>       IPA_NODE_REF (clone)->is_all_contexts_clone = true;
> -      for (i = 0; i < count; i++)
> -     vec_free (known_aggs[i].items);
> -      known_aggs.release ();
>       ret = true;
>     }
>   else
> diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
> index 6de060aa3fc..f8725d8dbfe 100644
> --- a/gcc/ipa-fnsummary.c
> +++ b/gcc/ipa-fnsummary.c
> @@ -306,9 +306,9 @@ set_hint_predicate (predicate **p, predicate 
> new_predicate)
>    the fact that parameter is indeed a constant.
> 
>    KNOWN_VALS is partial mapping of parameters of NODE to constant values.
> -   KNOWN_AGGS is a vector of aggreggate jump functions for each parameter.
> -   Return clause of possible truths. When INLINE_P is true, assume that we 
> are
> -   inlining.
> +   KNOWN_AGGS is a vector of aggreggate known offset/value set for each
> +   parameter.  Return clause of possible truths.  When INLINE_P is true, 
> assume
> +   that we are inlining.
> 
>    ERROR_MARK means compile time invariant.  */
> 
> @@ -316,8 +316,7 @@ static void
> evaluate_conditions_for_known_args (struct cgraph_node *node,
>                                   bool inline_p,
>                                   vec<tree> known_vals,
> -                                 vec<ipa_agg_jump_function_p>
> -                                 known_aggs,
> +                                 vec<ipa_agg_value_set> known_aggs,
>                                   clause_t *ret_clause,
>                                   clause_t *ret_nonspec_clause)
> {
> @@ -347,7 +346,7 @@ evaluate_conditions_for_known_args (struct cgraph_node 
> *node,
> 
>       if (c->agg_contents)
>       {
> -       struct ipa_agg_jump_function *agg;
> +       struct ipa_agg_value_set *agg;
> 
>         if (c->code == predicate::changed
>             && !c->by_ref
> @@ -356,7 +355,7 @@ evaluate_conditions_for_known_args (struct cgraph_node 
> *node,
> 
>         if (known_aggs.exists ())
>           {
> -           agg = known_aggs[c->operand_num];
> +           agg = &known_aggs[c->operand_num];
>             val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num],
>                                               c->offset, c->by_ref);
>           }
> @@ -420,12 +419,12 @@ evaluate_properties_for_edge (struct cgraph_edge *e, 
> bool inline_p,
>                             vec<tree> *known_vals_ptr,
>                             vec<ipa_polymorphic_call_context>
>                             *known_contexts_ptr,
> -                           vec<ipa_agg_jump_function_p> *known_aggs_ptr)
> +                           vec<ipa_agg_value_set> *known_aggs_ptr)
> {
>   struct cgraph_node *callee = e->callee->ultimate_alias_target ();
>   class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
>   vec<tree> known_vals = vNULL;
> -  vec<ipa_agg_jump_function_p> known_aggs = vNULL;
> +  vec<ipa_agg_value_set> known_aggs = vNULL;
> 
>   if (clause_ptr)
>     *clause_ptr = inline_p ? 0 : 1 << predicate::not_inlined_condition;
> @@ -438,15 +437,17 @@ evaluate_properties_for_edge (struct cgraph_edge *e, 
> bool inline_p,
>       && !e->call_stmt_cannot_inline_p
>       && ((clause_ptr && info->conds) || known_vals_ptr || 
> known_contexts_ptr))
>     {
> +      struct cgraph_node *caller;
>       class ipa_node_params *caller_parms_info, *callee_pi;
>       class ipa_edge_args *args = IPA_EDGE_REF (e);
>       class ipa_call_summary *es = ipa_call_summaries->get (e);
>       int i, count = ipa_get_cs_argument_count (args);
> 
>       if (e->caller->global.inlined_to)
> -     caller_parms_info = IPA_NODE_REF (e->caller->global.inlined_to);
> +     caller = e->caller->global.inlined_to;
>       else
> -     caller_parms_info = IPA_NODE_REF (e->caller);
> +     caller = e->caller;
> +      caller_parms_info = IPA_NODE_REF (caller);
>       callee_pi = IPA_NODE_REF (e->callee);
> 
>       if (count && (info->conds || known_vals_ptr))
> @@ -481,10 +482,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, 
> bool inline_p,
>         if (known_contexts_ptr)
>           (*known_contexts_ptr)[i]
>             = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
> -       /* TODO: When IPA-CP starts propagating and merging aggregate jump
> -          functions, use its knowledge of the caller too, just like the
> -          scalar case above.  */
> -       known_aggs[i] = &jf->agg;
> +
> +       known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info,
> +                                                     caller, &jf->agg);
>       }
>     }
>   else if (e->call_stmt && !e->call_stmt_cannot_inline_p
> @@ -516,7 +516,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool 
> inline_p,
>   if (known_aggs_ptr)
>     *known_aggs_ptr = known_aggs;
>   else
> -    known_aggs.release ();
> +    ipa_release_agg_values (known_aggs);
> }
> 
> 
> @@ -2662,7 +2662,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
>                             int *size, int *time,
>                             vec<tree> known_vals,
>                             vec<ipa_polymorphic_call_context> known_contexts,
> -                           vec<ipa_agg_jump_function_p> known_aggs)
> +                           vec<ipa_agg_value_set> known_aggs)
> {
>   tree target;
>   struct cgraph_node *callee;
> @@ -2711,7 +2711,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int 
> *size, int *min_size,
>                            int prob,
>                            vec<tree> known_vals,
>                            vec<ipa_polymorphic_call_context> known_contexts,
> -                          vec<ipa_agg_jump_function_p> known_aggs,
> +                          vec<ipa_agg_value_set> known_aggs,
>                            ipa_hints *hints)
> {
>   class ipa_call_summary *es = ipa_call_summaries->get (e);
> @@ -2746,7 +2746,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, 
> int *size,
>                             clause_t possible_truths,
>                             vec<tree> known_vals,
>                             vec<ipa_polymorphic_call_context> known_contexts,
> -                           vec<ipa_agg_jump_function_p> known_aggs)
> +                           vec<ipa_agg_value_set> known_aggs)
> {
>   struct cgraph_edge *e;
>   for (e = node->callees; e; e = e->next_callee)
> @@ -2809,7 +2809,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
>                            clause_t nonspec_possible_truths,
>                            vec<tree> known_vals,
>                            vec<ipa_polymorphic_call_context> known_contexts,
> -                          vec<ipa_agg_jump_function_p> known_aggs,
> +                          vec<ipa_agg_value_set> known_aggs,
>                            int *ret_size, int *ret_min_size,
>                            sreal *ret_time,
>                            sreal *ret_nonspecialized_time,
> @@ -2945,7 +2945,7 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node 
> *node,
>                                  vec<tree> known_vals,
>                                  vec<ipa_polymorphic_call_context>
>                                  known_contexts,
> -                                vec<ipa_agg_jump_function_p> known_aggs,
> +                                vec<ipa_agg_value_set> known_aggs,
>                                  int *ret_size, sreal *ret_time,
>                                  sreal *ret_nonspec_time,
>                                  ipa_hints *hints)
> diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h
> index 173d3f2a652..7e561dab400 100644
> --- a/gcc/ipa-fnsummary.h
> +++ b/gcc/ipa-fnsummary.h
> @@ -260,7 +260,7 @@ void inline_analyze_function (struct cgraph_node *node);
> void estimate_ipcp_clone_size_and_time (struct cgraph_node *,
>                                       vec<tree>,
>                                       vec<ipa_polymorphic_call_context>,
> -                                     vec<ipa_agg_jump_function_p>,
> +                                     vec<ipa_agg_value_set>,
>                                       int *, sreal *, sreal *,
>                                       ipa_hints *);
> void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge);
> @@ -274,13 +274,13 @@ void evaluate_properties_for_edge (struct cgraph_edge 
> *e, bool inline_p,
>                                  vec<tree> *known_vals_ptr,
>                                  vec<ipa_polymorphic_call_context>
>                                  *known_contexts_ptr,
> -                                vec<ipa_agg_jump_function_p> *);
> +                                vec<ipa_agg_value_set> *);
> void estimate_node_size_and_time (struct cgraph_node *node,
>                                 clause_t possible_truths,
>                                 clause_t nonspec_possible_truths,
>                                 vec<tree> known_vals,
>                                 vec<ipa_polymorphic_call_context>,
> -                               vec<ipa_agg_jump_function_p> known_aggs,
> +                               vec<ipa_agg_value_set> known_aggs,
>                                 int *ret_size, int *ret_min_size,
>                                 sreal *ret_time,
>                                 sreal *ret_nonspecialized_time,
> diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
> index a66af277d03..bf4e6ea3392 100644
> --- a/gcc/ipa-inline-analysis.c
> +++ b/gcc/ipa-inline-analysis.c
> @@ -127,7 +127,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
>   clause_t clause, nonspec_clause;
>   vec<tree> known_vals;
>   vec<ipa_polymorphic_call_context> known_contexts;
> -  vec<ipa_agg_jump_function_p> known_aggs;
> +  vec<ipa_agg_value_set> known_aggs;
>   class ipa_call_summary *es = ipa_call_summaries->get (edge);
>   int min_size;
> 
> @@ -154,7 +154,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
> 
>   known_vals.release ();
>   known_contexts.release ();
> -  known_aggs.release ();
> +  ipa_release_agg_values (known_aggs);
>   gcc_checking_assert (size >= 0);
>   gcc_checking_assert (time >= 0);
> 
> @@ -186,7 +186,7 @@ do_estimate_edge_size (struct cgraph_edge *edge)
>   clause_t clause, nonspec_clause;
>   vec<tree> known_vals;
>   vec<ipa_polymorphic_call_context> known_contexts;
> -  vec<ipa_agg_jump_function_p> known_aggs;
> +  vec<ipa_agg_value_set> known_aggs;
> 
>   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
> 
> @@ -211,7 +211,7 @@ do_estimate_edge_size (struct cgraph_edge *edge)
>                              NULL, NULL, vNULL);
>   known_vals.release ();
>   known_contexts.release ();
> -  known_aggs.release ();
> +  ipa_release_agg_values (known_aggs);
>   return size;
> }
> 
> @@ -227,7 +227,7 @@ do_estimate_edge_hints (struct cgraph_edge *edge)
>   clause_t clause, nonspec_clause;
>   vec<tree> known_vals;
>   vec<ipa_polymorphic_call_context> known_contexts;
> -  vec<ipa_agg_jump_function_p> known_aggs;
> +  vec<ipa_agg_value_set> known_aggs;
> 
>   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
> 
> @@ -252,7 +252,7 @@ do_estimate_edge_hints (struct cgraph_edge *edge)
>                              NULL, NULL, &hints, vNULL);
>   known_vals.release ();
>   known_contexts.release ();
> -  known_aggs.release ();
> +  ipa_release_agg_values (known_aggs);
>   hints |= simple_edge_hints (edge);
>   return hints;
> }
> diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> index a23aa2590a0..be281293eb7 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -359,18 +359,45 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct 
> cgraph_edge *cs)
> 
>         fprintf (f, "         Aggregate passed by %s:\n",
>                  jump_func->agg.by_ref ? "reference" : "value");
> -       FOR_EACH_VEC_SAFE_ELT (jump_func->agg.items, j, item)
> +       FOR_EACH_VEC_ELT (*jump_func->agg.items, j, item)
>           {
>             fprintf (f, "           offset: " HOST_WIDE_INT_PRINT_DEC ", ",
>                      item->offset);
> -           if (TYPE_P (item->value))
> -             fprintf (f, "clobber of " HOST_WIDE_INT_PRINT_DEC " bits",
> -                      tree_to_uhwi (TYPE_SIZE (item->value)));
> -           else
> +           fprintf (f, "type: ");
> +           print_generic_expr (f, item->type);
> +           fprintf (f, ", ");
> +           if (item->jftype == IPA_JF_PASS_THROUGH)
> +             fprintf (f, "PASS THROUGH: %d,",
> +                      item->value.pass_through.formal_id);
> +           else if (item->jftype == IPA_JF_LOAD_AGG)
> +             {
> +               fprintf (f, "LOAD AGG: %d",
> +                        item->value.pass_through.formal_id);
> +               fprintf (f, " [offset: " HOST_WIDE_INT_PRINT_DEC ", by %s],",
> +                        item->value.load_agg.offset,
> +                        item->value.load_agg.by_ref ? "reference"
> +                                                    : "value");
> +             }
> +
> +           if (item->jftype == IPA_JF_PASS_THROUGH
> +               || item->jftype == IPA_JF_LOAD_AGG)
> +             {
> +               fprintf (f, " op %s",
> +                  get_tree_code_name (item->value.pass_through.operation));
> +               if (item->value.pass_through.operation != NOP_EXPR)
> +                 {
> +                   fprintf (f, " ");
> +                   print_generic_expr (f, item->value.pass_through.operand);
> +                 }
> +             }
> +           else if (item->jftype == IPA_JF_CONST)
>               {
> -               fprintf (f, "cst: ");
> -               print_generic_expr (f, item->value);
> +               fprintf (f, "CONST: ");
> +               print_generic_expr (f, item->value.constant);
>               }
> +           else if (item->jftype == IPA_JF_UNKNOWN)
> +             fprintf (f, "UNKNOWN: " HOST_WIDE_INT_PRINT_DEC " bits",
> +                      tree_to_uhwi (TYPE_SIZE (item->type)));
>             fprintf (f, "\n");
>           }
>       }
> @@ -1135,6 +1162,67 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
>   return false;
> }
> 
> +/* If STMT is an assignment that loads a value from a parameter declaration,
> +   or from an aggregate passed as the parameter either by value or reference,
> +   return the index of the parameter in ipa_node_params.  Otherwise return 
> -1.
> +
> +   FBI holds gathered information about the function.  INFO describes
> +   parameters of the function, STMT is the assignment statement.  If it is a
> +   memory load from an aggregate, *OFFSET_P is filled with offset within the
> +   aggregate, and *BY_REF_P specifies whether the aggregate is passed by
> +   reference.  */
> +
> +static int
> +load_from_unmodified_param_or_agg (struct ipa_func_body_info *fbi,
> +                                class ipa_node_params *info,
> +                                gimple *stmt,
> +                                HOST_WIDE_INT *offset_p,
> +                                bool *by_ref_p)
> +{
> +  int index = load_from_unmodified_param (fbi, info->descriptors, stmt);
> +  poly_int64 size;
> +
> +  /* Load value from a parameter declaration.  */
> +  if (index >= 0)
> +    {
> +      *offset_p = -1;
> +      return index;
> +    }
> +
> +  if (!gimple_assign_load_p (stmt))
> +    return -1;
> +
> +  tree rhs = gimple_assign_rhs1 (stmt);
> +
> +  /* Skip memory reference containing VIEW_CONVERT_EXPR.  */
> +  for (tree t = rhs; handled_component_p (t); t = TREE_OPERAND (t, 0))
> +    if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
> +      return -1;
> +
> +  /* Skip memory reference containing bit-field.  */
> +  if (TREE_CODE (rhs) == BIT_FIELD_REF
> +      || contains_bitfld_component_ref_p (rhs))
> +    return -1;
> +
> +  if (!ipa_load_from_parm_agg (fbi, info->descriptors, stmt, rhs, &index,
> +                            offset_p, &size, by_ref_p))
> +    return -1;
> +
> +  gcc_assert (!maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (rhs))),
> +                      size));
> +  if (!*by_ref_p)
> +    {
> +      tree param_type = ipa_get_type (info, index);
> +
> +      if (!param_type || !AGGREGATE_TYPE_P (param_type))
> +     return -1;
> +    }
> +  else if (TREE_THIS_VOLATILE (rhs))
> +    return -1;
> +
> +  return index;
> +}
> +
> /* Given that an actual argument is an SSA_NAME (given in NAME) and is a 
> result
>    of an assignment statement STMT, try to determine whether we are actually
>    handling any of the following cases and construct an appropriate jump
> @@ -1438,11 +1526,11 @@ type_like_member_ptr_p (tree type, tree *method_ptr, 
> tree *delta)
> }
> 
> /* If RHS is an SSA_NAME and it is defined by a simple copy assign statement,
> -   return the rhs of its defining statement.  Otherwise return RHS as it
> -   is.  */
> +   return the rhs of its defining statement, and this statement is stored in
> +   *RHS_STMT.  Otherwise return RHS as it is.  */
> 
> static inline tree
> -get_ssa_def_if_simple_copy (tree rhs)
> +get_ssa_def_if_simple_copy (tree rhs, gimple **rhs_stmt)
> {
>   while (TREE_CODE (rhs) == SSA_NAME && !SSA_NAME_IS_DEFAULT_DEF (rhs))
>     {
> @@ -1452,25 +1540,31 @@ get_ssa_def_if_simple_copy (tree rhs)
>       rhs = gimple_assign_rhs1 (def_stmt);
>       else
>       break;
> +      *rhs_stmt = def_stmt;
>     }
>   return rhs;
> }
> 
> -/* Simple linked list, describing known contents of an aggregate before
> -   call.  */
> +/* Simple linked list, describing contents of an aggregate before call.  */
> 
> struct ipa_known_agg_contents_list
> {
>   /* Offset and size of the described part of the aggregate.  */
>   HOST_WIDE_INT offset, size;
> -  /* Known constant value or NULL if the contents is known to be unknown.  */
> -  tree constant;
> +
> +  /* Type of the described part of the aggregate.  */
> +  tree type;
> +
> +  /* Known constant value or jump function data describing contents.  */
> +  struct ipa_load_agg_data value;
> +
>   /* Pointer to the next structure in the list.  */
>   struct ipa_known_agg_contents_list *next;
> };
> 
> -/* Add a known content item into a linked list of ipa_known_agg_contents_list
> -   structure, in which all elements are sorted ascendingly by offset.  */
> +/* Add an aggregate content item into a linked list of
> +   ipa_known_agg_contents_list structure, in which all elements
> +   are sorted ascendingly by offset.  */
> 
> static inline void
> add_to_agg_contents_list (struct ipa_known_agg_contents_list **plist,
> @@ -1490,7 +1584,7 @@ add_to_agg_contents_list (struct 
> ipa_known_agg_contents_list **plist,
>   *plist = item;
> }
> 
> -/* Check whether a given known content is clobbered by certain element in
> +/* Check whether a given aggregate content is clobbered by certain element in
>    a linked list of ipa_known_agg_contents_list.  */
> 
> static inline bool
> @@ -1510,27 +1604,189 @@ clobber_by_agg_contents_list_p (struct 
> ipa_known_agg_contents_list *list,
> }
> 
> /* Build aggregate jump function from LIST, assuming there are exactly
> -   CONST_COUNT constant entries there and that offset of the passed argument
> +   VALUE_COUNT entries there and that offset of the passed argument
>    is ARG_OFFSET and store it into JFUNC.  */
> 
> static void
> build_agg_jump_func_from_list (struct ipa_known_agg_contents_list *list,
> -                            int const_count, HOST_WIDE_INT arg_offset,
> +                            int value_count, HOST_WIDE_INT arg_offset,
>                              struct ipa_jump_func *jfunc)
> {
> -  vec_alloc (jfunc->agg.items, const_count);
> -  while (list)
> +  vec_alloc (jfunc->agg.items, value_count);
> +  for (; list; list = list->next)
> +    {
> +      struct ipa_agg_jf_item item;
> +      tree operand = list->value.pass_through.operand;
> +
> +      if (list->value.pass_through.formal_id >= 0)
> +     {
> +       /* Content value is derived from some formal paramerter.  */
> +       if (list->value.offset >= 0)
> +         item.jftype = IPA_JF_LOAD_AGG;
> +       else
> +         item.jftype = IPA_JF_PASS_THROUGH;
> +
> +       item.value.load_agg = list->value;
> +       if (operand)
> +         item.value.pass_through.operand
> +                             = unshare_expr_without_location (operand);
> +     }
> +      else if (operand)
> +     {
> +       /* Content value is known constant.  */
> +       item.jftype = IPA_JF_CONST;
> +       item.value.constant = unshare_expr_without_location (operand);
> +     }
> +      else
> +     continue;
> +
> +      item.type = list->type;
> +      gcc_assert (tree_to_shwi (TYPE_SIZE (list->type)) == list->size);
> +
> +      item.offset = list->offset - arg_offset;
> +      gcc_assert ((item.offset % BITS_PER_UNIT) == 0);
> +
> +      jfunc->agg.items->quick_push (item);
> +    }
> +}
> +
> +/* Given an assignment statement STMT, try to collect information into
> +   AGG_VALUE that will be used to construct jump function for RHS of the
> +   assignment, from which content value of an aggregate part comes.
> +
> +   Besides constant and simple pass-through jump functions, also try to
> +   identify whether it matches the following pattern that can be described by
> +   a load-value-from-aggregate jump function, which is a derivative of simple
> +   pass-through jump function.
> +
> +     foo (int *p)
> +     {
> +       ...
> +
> +       *(q_5 + 4) = *(p_3(D) + 28) op 1;
> +       bar (q_5);
> +     }
> +
> +   Since load-value-from-aggregate jump function data structure is 
> informative
> +   enough to describe constant and simple pass-through jump function, here we
> +   do not need a jump function type, merely use FORMAL_ID and OPERAND in
> +   IPA_LOAD_AGG_DATA to disginguish different jump functions.  */
> +
> +static void
> +compute_assign_agg_jump_func (struct ipa_func_body_info *fbi,
> +                           struct ipa_load_agg_data *agg_value,
> +                           gimple *stmt)
> +{
> +  tree lhs = gimple_assign_lhs (stmt);
> +  tree rhs1 = gimple_assign_rhs1 (stmt);
> +  enum tree_code code;
> +  int index = -1;
> +
> +  /* Initialize jump function data for the aggregate part.  */
> +  memset (agg_value, 0, sizeof (*agg_value));
> +  agg_value->pass_through.operation = NOP_EXPR;
> +  agg_value->pass_through.formal_id = -1;
> +  agg_value->offset = -1;
> +
> +  if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))  /* TODO: Support aggregate type.  
> */
> +      || TREE_THIS_VOLATILE (lhs)
> +      || TREE_CODE (lhs) == BIT_FIELD_REF
> +      || contains_bitfld_component_ref_p (lhs))
> +    return;
> +
> +  /* Skip SSA copies.  */
> +  while (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS)
> +    {
> +      if (TREE_CODE (rhs1) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (rhs1))
> +     break;
> +
> +      if (!is_gimple_assign (stmt = SSA_NAME_DEF_STMT (rhs1)))
> +     return;
> +
> +      rhs1 = gimple_assign_rhs1 (stmt);
> +    }
> +
> +  code = gimple_assign_rhs_code (stmt);
> +  switch (gimple_assign_rhs_class (stmt))
>     {
> -      if (list->constant)
> +    case GIMPLE_SINGLE_RHS:
> +      if (is_gimple_ip_invariant (rhs1))
>       {
> -       struct ipa_agg_jf_item item;
> -       item.offset = list->offset - arg_offset;
> -       gcc_assert ((item.offset % BITS_PER_UNIT) == 0);
> -       item.value = unshare_expr_without_location (list->constant);
> -       jfunc->agg.items->quick_push (item);
> +       agg_value->pass_through.operand = rhs1;
> +       return;
>       }
> -      list = list->next;
> +      code = NOP_EXPR;
> +      break;
> +
> +    case GIMPLE_UNARY_RHS:
> +      /* NOTE: A GIMPLE_UNARY_RHS operation might not be tcc_unary
> +      (truth_not_expr is example), GIMPLE_BINARY_RHS does not imply
> +      tcc_binary, this subtleness is somewhat misleading.
> +      
> +      Since tcc_unary is widely used in IPA-CP code to check an operation
> +      with one operand, here we only allow tc_unary operation to avoid
> +      possible problem.  Then we can use (opclass == tc_unary) or not to
> +      distinguish unary and binary.  */
> +      if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P (code))
> +     return;
> +
> +      rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt);
> +      break;
> +
> +    case GIMPLE_BINARY_RHS:
> +      {
> +     gimple *rhs1_stmt = stmt;
> +     gimple *rhs2_stmt = stmt;
> +     tree rhs2 = gimple_assign_rhs2 (stmt);
> +
> +     rhs1 = get_ssa_def_if_simple_copy (rhs1, &rhs1_stmt);
> +     rhs2 = get_ssa_def_if_simple_copy (rhs2, &rhs2_stmt);
> +
> +     if (is_gimple_ip_invariant (rhs2))
> +       {
> +         agg_value->pass_through.operand = rhs2;
> +         stmt = rhs1_stmt;
> +       }
> +     else if (is_gimple_ip_invariant (rhs1))
> +       {
> +         if (TREE_CODE_CLASS (code) == tcc_comparison)
> +           code = swap_tree_comparison (code);
> +         else if (!commutative_tree_code (code))
> +           return;
> +
> +         agg_value->pass_through.operand = rhs1;
> +         stmt = rhs2_stmt;
> +         rhs1 = rhs2;
> +       }
> +     else
> +       return;
> +
> +     if (TREE_CODE_CLASS (code) != tcc_comparison
> +         && !useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs1)))
> +       return;
> +      }
> +      break;
> +
> +    default:
> +      return;
> +  }
> +
> +  if (TREE_CODE (rhs1) != SSA_NAME)
> +    index = load_from_unmodified_param_or_agg (fbi, fbi->info, stmt,
> +                                            &agg_value->offset,
> +                                            &agg_value->by_ref);
> +  else if (SSA_NAME_IS_DEFAULT_DEF (rhs1))
> +    index = ipa_get_param_decl_index (fbi->info, SSA_NAME_VAR (rhs1));
> +
> +  if (index >= 0)
> +    {
> +      if (agg_value->offset >= 0)
> +     agg_value->type = TREE_TYPE (rhs1);
> +      agg_value->pass_through.formal_id = index;
> +      agg_value->pass_through.operation = code;
>     }
> +  else
> +    agg_value->pass_through.operand = NULL_TREE;
> }
> 
> /* If STMT is a memory store to the object whose address is BASE, extract
> @@ -1540,26 +1796,19 @@ build_agg_jump_func_from_list (struct 
> ipa_known_agg_contents_list *list,
>    is expected to be in form of MEM_REF expression.  */
> 
> static bool
> -extract_mem_content (gimple *stmt, tree base, bool check_ref,
> +extract_mem_content (struct ipa_func_body_info *fbi,
> +                  gimple *stmt, tree base, bool check_ref,
>                    struct ipa_known_agg_contents_list *content)
> {
>   HOST_WIDE_INT lhs_offset, lhs_size;
> -  tree lhs, rhs, lhs_base;
>   bool reverse;
> 
> -  if (!gimple_assign_single_p (stmt))
> -    return false;
> -
> -  lhs = gimple_assign_lhs (stmt);
> -  rhs = gimple_assign_rhs1 (stmt);
> -
> -  if (!is_gimple_reg_type (TREE_TYPE (rhs))
> -      || TREE_CODE (lhs) == BIT_FIELD_REF
> -      || contains_bitfld_component_ref_p (lhs))
> +  if (!is_gimple_assign (stmt))
>     return false;
> 
> -  lhs_base = get_ref_base_and_extent_hwi (lhs, &lhs_offset,
> -                                       &lhs_size, &reverse);
> +  tree lhs = gimple_assign_lhs (stmt);
> +  tree lhs_base = get_ref_base_and_extent_hwi (lhs, &lhs_offset, &lhs_size,
> +                                            &reverse);
>   if (!lhs_base)
>     return false;
> 
> @@ -1573,32 +1822,31 @@ extract_mem_content (gimple *stmt, tree base, bool 
> check_ref,
>   else if (lhs_base != base)
>     return false;
> 
> -  rhs = get_ssa_def_if_simple_copy (rhs);
> -
> -  content->size = lhs_size;
>   content->offset = lhs_offset;
> -  content->constant = is_gimple_ip_invariant (rhs) ? rhs : NULL_TREE;
> +  content->size = lhs_size;
> +  content->type = TREE_TYPE (lhs);
>   content->next = NULL;
> 
> +  compute_assign_agg_jump_func (fbi, &content->value, stmt);
>   return true;
> }
> 
> /* Traverse statements from CALL backwards, scanning whether an aggregate 
> given
> -   in ARG is filled in with constant values.  ARG can either be an aggregate
> -   expression or a pointer to an aggregate.  ARG_TYPE is the type of the
> -   aggregate.  JFUNC is the jump function into which the constants are
> -   subsequently stored.  AA_WALK_BUDGET_P points to limit on number of
> -   statements we allow get_continuation_for_phi to examine.  */
> +   in ARG is filled in constant or value that is derived from caller's formal
> +   parameter in the way described by some kind of jump function.  FBI is the
> +   context of the caller function for interprocedural analysis.  ARG can 
> either
> +   be an aggregate expression or a pointer to an aggregate.  ARG_TYPE is the
> +   type of the aggregate.  JFUNC is the jump function for the aggregate.  */
> 
> static void
> -determine_known_aggregate_parts (gcall *call, tree arg,
> +determine_known_aggregate_parts (struct ipa_func_body_info *fbi,
> +                              gcall *call, tree arg,
>                                tree arg_type,
> -                              struct ipa_jump_func *jfunc,
> -                              unsigned *aa_walk_budget_p)
> +                              struct ipa_jump_func *jfunc)
> {
>   struct ipa_known_agg_contents_list *list = NULL, *all_list = NULL;
>   bitmap visited = NULL;
> -  int item_count = 0, const_count = 0;
> +  int item_count = 0, value_count = 0;
>   int ipa_max_agg_items = PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS);
>   HOST_WIDE_INT arg_offset, arg_size;
>   tree arg_base;
> @@ -1677,7 +1925,7 @@ determine_known_aggregate_parts (gcall *call, tree arg,
>       if (gimple_code (stmt) == GIMPLE_PHI)
>       {
>         dom_vuse = get_continuation_for_phi (stmt, &r, true,
> -                                            *aa_walk_budget_p,
> +                                            fbi->aa_walk_budget,
>                                              &visited, false, NULL, NULL);
>         continue;
>       }
> @@ -1687,12 +1935,13 @@ determine_known_aggregate_parts (gcall *call, tree 
> arg,
>         struct ipa_known_agg_contents_list *content
>                       = XALLOCA (struct ipa_known_agg_contents_list);
> 
> -       if (!extract_mem_content (stmt, arg_base, check_ref, content))
> +       if (!extract_mem_content (fbi, stmt, arg_base, check_ref, content))
>           break;
> 
>         /* Now we get a dominating virtual operand, and need to check
>            whether its value is clobbered any other dominating one.  */
> -       if (content->constant
> +       if ((content->value.pass_through.formal_id >= 0
> +            || content->value.pass_through.operand)
>             && !clobber_by_agg_contents_list_p (all_list, content))
>           {
>             struct ipa_known_agg_contents_list *copy
> @@ -1702,7 +1951,7 @@ determine_known_aggregate_parts (gcall *call, tree arg,
>                operands, whose definitions can finally reach the call.  */
>             add_to_agg_contents_list (&list, (*copy = *content, copy));
> 
> -           if (++const_count == ipa_max_agg_items)
> +           if (++value_count == ipa_max_agg_items)
>               break;
>           }
> 
> @@ -1720,12 +1969,12 @@ determine_known_aggregate_parts (gcall *call, tree 
> arg,
> 
>   /* Third stage just goes over the list and creates an appropriate vector of
>      ipa_agg_jf_item structures out of it, of course only if there are
> -     any known constants to begin with.  */
> +     any meaningful items to begin with.  */
> 
> -  if (const_count)
> +  if (value_count)
>     {
>       jfunc->agg.by_ref = by_ref;
> -      build_agg_jump_func_from_list (list, const_count, arg_offset, jfunc);
> +      build_agg_jump_func_from_list (list, value_count, arg_offset, jfunc);
>     }
> }
> 
> @@ -2017,8 +2266,7 @@ ipa_compute_jump_functions_for_edge (struct 
> ipa_func_body_info *fbi,
>             || !ipa_get_jf_ancestor_agg_preserved (jfunc))
>         && (AGGREGATE_TYPE_P (TREE_TYPE (arg))
>             || POINTER_TYPE_P (param_type)))
> -     determine_known_aggregate_parts (call, arg, param_type, jfunc,
> -                                      &fbi->aa_walk_budget);
> +     determine_known_aggregate_parts (fbi, call, arg, param_type, jfunc);
>     }
>   if (!useful_context)
>     vec_free (args->polymorphic_call_contexts);
> @@ -2661,6 +2909,72 @@ update_jump_functions_after_inlining (struct 
> cgraph_edge *cs,
>       class ipa_polymorphic_call_context *dst_ctx
>       = ipa_get_ith_polymorhic_call_context (args, i);
> 
> +      if (dst->agg.items)
> +     {
> +       struct ipa_agg_jf_item *item;
> +       int j;
> +
> +       FOR_EACH_VEC_ELT (*dst->agg.items, j, item)
> +         {
> +           int dst_fid;
> +           struct ipa_jump_func *src;
> +
> +           if (item->jftype != IPA_JF_PASS_THROUGH
> +               && item->jftype != IPA_JF_LOAD_AGG)
> +             continue;
> +
> +           dst_fid = item->value.pass_through.formal_id;
> +           if (dst_fid >= ipa_get_cs_argument_count (top))
> +             {
> +               item->jftype = IPA_JF_UNKNOWN;
> +               continue;
> +             }
> +
> +           item->value.pass_through.formal_id = -1;
> +           src = ipa_get_ith_jump_func (top, dst_fid);
> +           if (src->type == IPA_JF_CONST)
> +             {
> +               if (item->jftype == IPA_JF_PASS_THROUGH
> +                   && item->value.pass_through.operation == NOP_EXPR)
> +                 {
> +                   item->jftype = IPA_JF_CONST;
> +                   item->value.constant = src->value.constant.value;
> +                   continue;
> +                 }
> +             }
> +           else if (src->type == IPA_JF_PASS_THROUGH
> +                    && src->value.pass_through.operation == NOP_EXPR)
> +             {
> +               if (item->jftype == IPA_JF_PASS_THROUGH
> +                   || !item->value.load_agg.by_ref
> +                   || src->value.pass_through.agg_preserved)
> +                 item->value.pass_through.formal_id
> +                             = src->value.pass_through.formal_id;
> +             }
> +           else if (src->type == IPA_JF_ANCESTOR)
> +             {
> +               if (item->jftype == IPA_JF_PASS_THROUGH)
> +                 {
> +                   if (!src->value.ancestor.offset)
> +                     item->value.pass_through.formal_id
> +                             = src->value.ancestor.formal_id;
> +                 }
> +               else if (src->value.ancestor.agg_preserved)
> +                 {
> +                   gcc_checking_assert (item->value.load_agg.by_ref);
> +
> +                   item->value.pass_through.formal_id
> +                              = src->value.ancestor.formal_id;
> +                   item->value.load_agg.offset
> +                             += src->value.ancestor.offset;
> +                 }
> +             }
> +
> +           if (item->value.pass_through.formal_id < 0)
> +             item->jftype = IPA_JF_UNKNOWN;
> +         }
> +     }
> +
>       if (dst->type == IPA_JF_ANCESTOR)
>       {
>         struct ipa_jump_func *src;
> @@ -2700,8 +3014,11 @@ update_jump_functions_after_inlining (struct 
> cgraph_edge *cs,
>               }
>           }
> 
> -       if (src->agg.items
> -           && (dst->value.ancestor.agg_preserved || !src->agg.by_ref))
> +       /* Parameter and argument in ancestor jump function must be pointer
> +          type, which means access to aggregate must be by-reference.  */
> +       gcc_checking_assert (!src->agg.items || src->agg.by_ref);
> +
> +       if (src->agg.items && dst->value.ancestor.agg_preserved)
>           {
>             struct ipa_agg_jf_item *item;
>             int j;
> @@ -3093,18 +3410,19 @@ 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 aggregate jump function AGG 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, 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.  */
> 
> tree
> -ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, tree scalar,
> +ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
>                           HOST_WIDE_INT offset, bool by_ref,
>                           bool *from_global_constant)
> {
> -  struct ipa_agg_jf_item *item;
> +  struct ipa_agg_value *item;
>   int i;
> 
>   if (scalar)
> @@ -3122,7 +3440,7 @@ ipa_find_agg_cst_for_param (struct 
> ipa_agg_jump_function *agg, tree scalar,
>       || by_ref != agg->by_ref)
>     return NULL;
> 
> -  FOR_EACH_VEC_SAFE_ELT (agg->items, i, item)
> +  FOR_EACH_VEC_ELT (agg->items, i, item)
>     if (item->offset == offset)
>       {
>       /* Currently we do not have clobber values, return NULL for them once
> @@ -3218,11 +3536,13 @@ try_decrement_rdesc_refcount (struct ipa_jump_func 
> *jfunc)
>    pointer formal parameter described by jump function JFUNC.  TARGET_TYPE is
>    the type of the parameter to which the result of JFUNC is passed.  If it 
> can
>    be determined, return the newly direct edge, otherwise return NULL.
> -   NEW_ROOT_INFO is the node info that JFUNC lattices are relative to.  */
> +   NEW_ROOT and NEW_ROOT_INFO is the node and its info that JFUNC lattices 
> are
> +   relative to.  */
> 
> static struct cgraph_edge *
> try_make_edge_direct_simple_call (struct cgraph_edge *ie,
>                                 struct ipa_jump_func *jfunc, tree target_type,
> +                               struct cgraph_node *new_root,
>                                 class ipa_node_params *new_root_info)
> {
>   struct cgraph_edge *cs;
> @@ -3232,10 +3552,14 @@ try_make_edge_direct_simple_call (struct cgraph_edge 
> *ie,
>   if (agg_contents)
>     {
>       bool from_global_constant;
> -      target = ipa_find_agg_cst_for_param (&jfunc->agg, scalar,
> +      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)
> @@ -3289,12 +3613,16 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, 
> tree target)
>    call based on a formal parameter which is described by jump function JFUNC
>    and if it can be determined, make it direct and return the direct edge.
>    Otherwise, return NULL.  CTX describes the polymorphic context that the
> -   parameter the call is based on brings along with it.  */
> +   parameter the call is based on brings along with it.  NEW_ROOT and
> +   NEW_ROOT_INFO is the node and its info that JFUNC lattices are relative
> +   to.  */
> 
> static struct cgraph_edge *
> try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
>                                  struct ipa_jump_func *jfunc,
> -                                class ipa_polymorphic_call_context ctx)
> +                                class ipa_polymorphic_call_context ctx,
> +                                struct cgraph_node *new_root,
> +                                class ipa_node_params *new_root_info)
> {
>   tree target = NULL;
>   bool speculative = false;
> @@ -3312,9 +3640,13 @@ try_make_edge_direct_virtual_call (struct cgraph_edge 
> *ie,
>       unsigned HOST_WIDE_INT offset;
>       tree scalar = (jfunc->type == IPA_JF_CONST) ? ipa_get_jf_constant 
> (jfunc)
>       : NULL;
> -      tree t = ipa_find_agg_cst_for_param (&jfunc->agg, scalar,
> +      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 ();
>       if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
>       {
>         bool can_refer;
> @@ -3405,14 +3737,15 @@ update_indirect_edges_after_inlining (struct 
> cgraph_edge *cs,
> {
>   class ipa_edge_args *top;
>   struct cgraph_edge *ie, *next_ie, *new_direct_edge;
> +  struct cgraph_node *new_root;
>   class ipa_node_params *new_root_info, *inlined_node_info;
>   bool res = false;
> 
>   ipa_check_create_edge_args ();
>   top = IPA_EDGE_REF (cs);
> -  new_root_info = IPA_NODE_REF (cs->caller->global.inlined_to
> -                             ? cs->caller->global.inlined_to
> -                             : cs->caller);
> +  new_root = cs->caller->global.inlined_to
> +             ? cs->caller->global.inlined_to : cs->caller;
> +  new_root_info = IPA_NODE_REF (new_root);
>   inlined_node_info = IPA_NODE_REF (cs->callee->function_symbol ());
> 
>   for (ie = node->indirect_calls; ie; ie = next_ie)
> @@ -3451,13 +3784,16 @@ update_indirect_edges_after_inlining (struct 
> cgraph_edge *cs,
>       {
>           ipa_polymorphic_call_context ctx;
>         ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc);
> -       new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx);
> +       new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx,
> +                                                            new_root,
> +                                                            new_root_info);
>       }
>       else
>       {
>         tree target_type =  ipa_get_type (inlined_node_info, param_index);
>         new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
>                                                             target_type,
> +                                                           new_root,
>                                                             new_root_info);
>       }
> 
> @@ -4125,6 +4461,8 @@ ipa_write_jump_function (struct output_block *ob,
>       bp_pack_value (&bp, jump_func->value.ancestor.agg_preserved, 1);
>       streamer_write_bitpack (&bp);
>       break;
> +    default:
> +      fatal_error (UNKNOWN_LOCATION, "invalid jump function in LTO stream");
>     }
> 
>   count = vec_safe_length (jump_func->agg.items);
> @@ -4138,8 +4476,36 @@ ipa_write_jump_function (struct output_block *ob,
> 
>   FOR_EACH_VEC_SAFE_ELT (jump_func->agg.items, i, item)
>     {
> +      stream_write_tree (ob, item->type, true);
>       streamer_write_uhwi (ob, item->offset);
> -      stream_write_tree (ob, item->value, true);
> +      streamer_write_uhwi (ob, item->jftype);
> +      switch (item->jftype)
> +     {
> +     case IPA_JF_UNKNOWN:
> +       break;
> +     case IPA_JF_CONST:
> +       stream_write_tree (ob, item->value.constant, true);
> +       break;
> +     case IPA_JF_PASS_THROUGH:
> +     case IPA_JF_LOAD_AGG:
> +       streamer_write_uhwi (ob, item->value.pass_through.operation);
> +       streamer_write_uhwi (ob, item->value.pass_through.formal_id);
> +       if (TREE_CODE_CLASS (item->value.pass_through.operation)
> +                                                     != tcc_unary)
> +         stream_write_tree (ob, item->value.pass_through.operand, true);
> +       if (item->jftype == IPA_JF_LOAD_AGG)
> +         {
> +           stream_write_tree (ob, item->value.load_agg.type, true);
> +           streamer_write_uhwi (ob, item->value.load_agg.offset);
> +           bp = bitpack_create (ob->main_stream);
> +           bp_pack_value (&bp, item->value.load_agg.by_ref, 1);
> +           streamer_write_bitpack (&bp);
> +         }
> +       break;
> +     default:
> +       fatal_error (UNKNOWN_LOCATION,
> +                    "invalid jump function in LTO stream");
> +     }
>     }
> 
>   bp = bitpack_create (ob->main_stream);
> @@ -4236,8 +4602,39 @@ ipa_read_jump_function (class lto_input_block *ib,
>   for (i = 0; i < count; i++)
>     {
>       struct ipa_agg_jf_item item;
> +      item.type = stream_read_tree (ib, data_in);
>       item.offset = streamer_read_uhwi (ib);
> -      item.value = stream_read_tree (ib, data_in);
> +      item.jftype = (enum jump_func_type) streamer_read_uhwi (ib);
> +
> +      switch (item.jftype)
> +     {
> +     case IPA_JF_UNKNOWN:
> +       break;
> +     case IPA_JF_CONST:
> +       item.value.constant = stream_read_tree (ib, data_in);
> +       break;
> +     case IPA_JF_PASS_THROUGH:
> +     case IPA_JF_LOAD_AGG:
> +       operation = (enum tree_code) streamer_read_uhwi (ib);
> +       item.value.pass_through.operation = operation;
> +       item.value.pass_through.formal_id = streamer_read_uhwi (ib);
> +       if (TREE_CODE_CLASS (operation) == tcc_unary)
> +         item.value.pass_through.operand = NULL_TREE;
> +       else
> +         item.value.pass_through.operand = stream_read_tree (ib, data_in);
> +       if (item.jftype == IPA_JF_LOAD_AGG)
> +         {
> +           struct bitpack_d bp;
> +           item.value.load_agg.type = stream_read_tree (ib, data_in);
> +           item.value.load_agg.offset = streamer_read_uhwi (ib);
> +           bp = streamer_read_bitpack (ib);
> +           item.value.load_agg.by_ref = bp_unpack_value (&bp, 1);
> +         }
> +       break;
> +     default:
> +       fatal_error (UNKNOWN_LOCATION,
> +                    "invalid jump function in LTO stream");
> +     }
>       if (prevails)
>         jump_func->agg.items->quick_push (item);
>     }
> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
> index 30948fb8854..bcdcc4b7f02 100644
> --- a/gcc/ipa-prop.h
> +++ b/gcc/ipa-prop.h
> @@ -39,6 +39,15 @@ along with GCC; see the file COPYING3.  If not see
>                   argument.
>    Unknown      - neither of the above.
> 
> +   IPA_JF_LOAD_AGG is a compound pass-through jump function, in which primary
> +   operation on formal parameter is memory dereference that loads a value 
> from
> +   a part of an aggregate, which is represented or pointed to by the formal
> +   parameter.  Moreover, an additional unary/binary operation can be applied 
> on
> +   the loaded value, and final result is passed as actual argument of callee
> +   (e.g. *(param_1(D) + 4) op 24 ).  It is meant to describe usage of 
> aggregate
> +   parameter or by-reference parameter referenced in argument passing, 
> commonly
> +   found in C++ and Fortran.
> +
>    IPA_JF_ANCESTOR is a special pass-through jump function, which means that
>    the result is an address of a part of the object pointed to by the formal
>    parameter to which the function refers.  It is mainly intended to represent
> @@ -60,6 +69,7 @@ enum jump_func_type
>   IPA_JF_UNKNOWN = 0,  /* newly allocated and zeroed jump functions default */
>   IPA_JF_CONST,             /* represented by field costant */
>   IPA_JF_PASS_THROUGH,            /* represented by field pass_through */
> +  IPA_JF_LOAD_AGG,       /* represented by field load_agg */
>   IPA_JF_ANCESTOR         /* represented by field ancestor */
> };
> 
> @@ -97,6 +107,26 @@ struct GTY(()) ipa_pass_through_data
>   unsigned agg_preserved : 1;
> };
> 
> +/* Structure holding data required to describe a load-value-from-aggregate
> +   jump function.  */
> +
> +struct GTY(()) ipa_load_agg_data
> +{
> +  /* Inherit from pass through jump function, describing unary/binary
> +     operation on the value loaded from aggregate that is represented or
> +     pointed to by the formal parameter, specified by formal_id in this
> +     pass_through jump function data structure.  */
> +  struct ipa_pass_through_data pass_through;
> +  /* Type of the value loaded from the aggregate.  */
> +  tree type;
> +  /* Offset at which the value is located within the aggregate.  */
> +  HOST_WIDE_INT offset;
> +  /* True if loaded by reference (the aggregate is pointed to by the formal
> +     parameter) or false if loaded by value (the aggregate is represented
> +     by the formal parameter).  */
> +  bool by_ref;
> +};
> +
> /* Structure holding data required to describe an ancestor pass-through
>    jump function.  */
> 
> @@ -110,38 +140,86 @@ struct GTY(()) ipa_ancestor_jf_data
>   unsigned agg_preserved : 1;
> };
> 
> -/* An element in an aggegate part of a jump function describing a known value
> -   at a given offset.  When it is part of a pass-through jump function with
> -   agg_preserved set or an ancestor jump function with agg_preserved set, all
> -   unlisted positions are assumed to be preserved but the value can be a type
> -   node, which means that the particular piece (starting at offset and having
> -   the size of the type) is clobbered with an unknown value.  When
> -   agg_preserved is false or the type of the containing jump function is
> -   different, all unlisted parts are assumed to be unknown and all values 
> must
> -   fulfill is_gimple_ip_invariant.  */
> +/* A jump function for an aggregate part at a given offset, which describes 
> how
> +   it content value is generated.  All unlisted positions are assumed to 
> have a
> +   value defined in an unknown way.  */
> 
> struct GTY(()) ipa_agg_jf_item
> {
> -  /* The offset at which the known value is located within the aggregate.  */
> +  /* The offset for the aggregate part.  */
>   HOST_WIDE_INT offset;
> 
> -  /* The known constant or type if this is a clobber.  */
> -  tree value;
> -};
> +  /* Data type of the aggregate part.  */
> +  tree type;
> 
> +  /* Jump function type.  */
> +  enum jump_func_type jftype;
> 
> -/* Aggregate jump function - i.e. description of contents of aggregates 
> passed
> -   either by reference or value.  */
> +  /* Represents a value of jump function. constant represents the actual 
> constant
> +     in constant jump function content.  pass_through is used only in simple 
> pass
> +     through jump function context.  load_agg is for 
> load-value-from-aggregate
> +     jump function context.  */
> +  union jump_func_agg_value
> +  {
> +    tree GTY ((tag ("IPA_JF_CONST"))) constant;
> +    struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) 
> pass_through;
> +    struct ipa_load_agg_data GTY ((tag ("IPA_JF_LOAD_AGG"))) load_agg;
> +  } GTY ((desc ("%1.jftype"))) value;
> +};
> +
> +/* Jump functions describing a set of aggregate contents.  */
> 
> struct GTY(()) ipa_agg_jump_function
> {
> -  /* Description of the individual items.  */
> +  /* Description of the individual jump function item.  */
>   vec<ipa_agg_jf_item, va_gc> *items;
> -  /* True if the data was passed by reference (as opposed to by value). */
> +  /* True if the data was passed by reference (as opposed to by value).  */
> +  bool by_ref;
> +};
> +
> +/* 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 GTY(()) ipa_agg_value
> +{
> +  /* The offset at which the known value is located within the aggregate.  */
> +  HOST_WIDE_INT offset;
> +
> +  /* The known constant.  */
> +  tree value;
> +};
> +
> +/* Structure describing a set of known offset/value for aggregate.  */
> +
> +struct GTY(()) 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;
> +
> +  void release ()
> +  {
> +    items.release ();
> +  }
> };
> 
> -typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p;
> +/* 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)
> +{
> +  ipa_agg_value_set *agg;
> +  int i;
> +
> +  FOR_EACH_VEC_ELT (aggs, i, agg)
> +    agg->release ();
> +  aggs.release ();
> +}
> 
> /* Information about zero/non-zero bits.  */
> class GTY(()) ipa_bits
> @@ -172,8 +250,8 @@ public:
>    types of jump functions supported.  */
> struct GTY (()) ipa_jump_func
> {
> -  /* Aggregate contants description.  See struct ipa_agg_jump_function and 
> its
> -     description.  */
> +  /* Aggregate jump function description.  See struct ipa_agg_jump_function
> +     and its description.  */
>   struct ipa_agg_jump_function agg;
> 
>   /* Information about zero/non-zero bits.  The pointed to structure is shared
> @@ -742,9 +820,9 @@ bool ipa_propagate_indirect_call_infos (struct 
> cgraph_edge *cs,
> 
> /* Indirect edge and binfo processing.  */
> tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
> -                                vec<tree> ,
> +                                vec<tree>,
>                                  vec<ipa_polymorphic_call_context>,
> -                                vec<ipa_agg_jump_function_p>,
> +                                vec<ipa_agg_value_set>,
>                                  bool *);
> struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, 
> tree,
>                                                   bool speculative = false);
> @@ -757,7 +835,7 @@ 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 (struct ipa_agg_jump_function *agg, tree 
> scalar,
> +tree ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
>                                HOST_WIDE_INT offset, bool by_ref,
>                                bool *from_global_constant = NULL);
> bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
> @@ -803,6 +881,9 @@ ipa_polymorphic_call_context ipa_context_from_jfunc 
> (ipa_node_params *,
>                                                    cgraph_edge *,
>                                                    int,
>                                                    ipa_jump_func *);
> +ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *,
> +                                             cgraph_node *,
> +                                             ipa_agg_jump_function *);
> 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);
> diff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-10.c 
> b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-10.c
> index 16d62e72c9a..c61e96a842b 100644
> --- a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-10.c
> +++ b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-10.c
> @@ -72,7 +72,7 @@ int caller2(void)
>   return sum;
> }
> 
> -/* { dg-final { scan-ipa-dump-times "offset: 0, cst: 1" 1 "cp" } } */
> -/* { dg-final { scan-ipa-dump-times "offset: 0, cst: 2" 1 "cp" } } */
> -/* { dg-final { scan-ipa-dump-times "offset: 0, cst: 3" 1 "cp" } } */
> -/* { dg-final { scan-ipa-dump-times "offset: 64, cst: 4" 1 "cp" } } */
> +/* { dg-final { scan-ipa-dump-times "offset: 0, type: int, CONST: 1" 1 "cp" 
> } } */
> +/* { dg-final { scan-ipa-dump-times "offset: 0, type: int, CONST: 2" 1 "cp" 
> } } */
> +/* { dg-final { scan-ipa-dump-times "offset: 0, type: int, CONST: 3" 1 "cp" 
> } } */
> +/* { dg-final { scan-ipa-dump-times "offset: 64, type: int, CONST: 4" 1 "cp" 
> } } */
> diff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c 
> b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c
> new file mode 100644
> index 00000000000..3c496eeef39
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c
> @@ -0,0 +1,77 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -fno-ipa-sra -fdump-ipa-cp-details -fno-early-inlining" 
> } */
> +/* { dg-add-options bind_pic_locally } */
> +
> +struct S
> +{
> +  int a, b, c;
> +};
> +
> +void *blah(int, void *);
> +
> +#define foo_body(p)\
> +{ \
> +  int i, c = (p)->c; \
> +  int b = (p)->b; \
> +  void *v = (void *) (p); \
> + \
> +  for (i= 0; i< c; i++) \
> +    v = blah(b + i, v); \
> +}
> +
> +static void __attribute__ ((noinline))
> +foo_v (struct S s)
> +{
> +  foo_body (&s);
> +}
> +
> +static void __attribute__ ((noinline))
> +foo_r (struct S *p)
> +{
> +  foo_body (p);
> +}
> +
> +static void
> +goo_v (int a, int *p)
> +{
> +  struct S s;
> +  s.a = 101;
> +  s.b = a % 7;
> +  s.c = *p + 6;
> +  foo_v (s);
> +}
> +
> +static void
> +goo_r (int a, struct S n)
> +{
> +  struct S s;
> +  s.a = 1;
> +  s.b = a + 5;
> +  s.c = -n.b;
> +  foo_r (&s);
> +}
> +
> +void
> +entry ()
> +{
> +  int a;
> +  int v;
> +  struct S s;
> +
> +  a = 9;
> +  v = 3;
> +  goo_v (a, &v);
> +
> +  a = 100;
> +  s.b = 18;
> +  goo_r (a, s);
> +}
> +
> +/* { dg-final { scan-ipa-dump "offset: 0, type: int, CONST: 1" "cp" } } */
> +/* { dg-final { scan-ipa-dump "offset: 32, type: int, PASS THROUGH: 0, op 
> plus_expr 5" "cp" } } */
> +/* { dg-final { scan-ipa-dump "offset: 64, type: int, LOAD AGG: 1 
> \\\[offset: 32, by value], op negate_expr" "cp" } } */
> +/* { dg-final { scan-ipa-dump "offset: 0, type: int, CONST: 101" "cp" } } */
> +/* { dg-final { scan-ipa-dump "offset: 32, type: int, PASS THROUGH: 0, op 
> trunc_mod_expr 7" "cp" } } */
> +/* { dg-final { scan-ipa-dump "offset: 64, type: int, LOAD AGG: 1 
> \\\[offset: 0, by reference], op plus_expr 6" "cp" } } */
> +/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=1, 
> 0\\\[32]=105, 0\\\[64]=-18" "cp" } } */
> +/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=101, 
> 0\\\[32]=2, 0\\\[64]=9" "cp" } } */
> -- 
> 2.17.1
> 

Reply via email to