diff mbox series

Convert ipcp_vr_lattice to type agnostic framework.

Message ID 20230517143030.465081-1-aldyh@redhat.com
State New
Headers show
Series Convert ipcp_vr_lattice to type agnostic framework. | expand

Commit Message

Aldy Hernandez May 17, 2023, 2:30 p.m. UTC
This converts the lattice to store ranges in Value_Range instead of
value_range (*) to make it type agnostic, and adjust all users
accordingly.

I think it is a good example on converting from static ranges to more
general, type agnostic ones.

I've been careful to make sure Value_Range never ends up on GC, since
it contains an int_range_max and can expand on-demand onto the heap.
Longer term storage for ranges should be done with vrange_storage, as
per the previous patch ("Provide an API for ipa_vr").

(*) I do know the Value_Range naming versus value_range is quite
annoying, but it was a judgement call last release for the eventual
migration to having "value_range" be a type agnostic range object.  We
will ultimately rename Value_Range to value_range.

OK for trunk?

gcc/ChangeLog:

	* ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
	(ipcp_vr_lattice::print): Call dump method.
	(ipcp_vr_lattice::meet_with): Adjust for m_vr being a
	Value_Range.
	(ipcp_vr_lattice::meet_with_1): Make argument a reference.
	(ipcp_vr_lattice::set_to_bottom): Add type argument.
	(set_all_contains_variable): Same.
	(initialize_node_lattices): Pass type when appropriate.
	(ipa_vr_operation_and_type_effects): Make type agnostic.
	(ipa_value_range_from_jfunc): Same.
	(propagate_vr_across_jump_function): Same.
	(propagate_constants_across_call): Same.
	* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
	(evaluate_properties_for_edge): Same.
	* ipa-prop.cc (ipcp_update_vr): Same.
	* ipa-prop.h (ipa_value_range_from_jfunc): Same.
	(ipa_range_set_and_normalize): Same.
---
 gcc/ipa-cp.cc        | 159 +++++++++++++++++++++++--------------------
 gcc/ipa-fnsummary.cc |  16 ++---
 gcc/ipa-prop.cc      |   2 +-
 gcc/ipa-prop.h       |  19 ++----
 4 files changed, 101 insertions(+), 95 deletions(-)

Comments

Aldy Hernandez May 17, 2023, 2:40 p.m. UTC | #1
On 5/17/23 16:30, Aldy Hernandez wrote:
> This converts the lattice to store ranges in Value_Range instead of
> value_range (*) to make it type agnostic, and adjust all users
> accordingly.
> 
> I think it is a good example on converting from static ranges to more
> general, type agnostic ones.
> 
> I've been careful to make sure Value_Range never ends up on GC, since
> it contains an int_range_max and can expand on-demand onto the heap.
> Longer term storage for ranges should be done with vrange_storage, as
> per the previous patch ("Provide an API for ipa_vr").
> 
> (*) I do know the Value_Range naming versus value_range is quite
> annoying, but it was a judgement call last release for the eventual
> migration to having "value_range" be a type agnostic range object.  We
> will ultimately rename Value_Range to value_range.

I forgot to mention.  This doesn't make IPA be type agnostic per se, 
just the range usage throughout.  The IPA code is still guarded by stuff 
like:

   if (!param_type
       || (!INTEGRAL_TYPE_P (param_type)
	  && !POINTER_TYPE_P (param_type)))
     return dest_lat->set_to_bottom (param_type);

It is up to the maintainers to adjust their passes, as I'm liable to 
break everything in the process ;-).

The above should probably become:

    if (!param_type || !Value_Range::supports_type_p (param_type))
...

This is the canonical way of querying whether a type is supported by 
Value_Range, the ranger temporary that can handle each supported type, 
and thus the ranger.  This is documented here:

// To query what types ranger and the entire ecosystem can support,
// use Value_Range::supports_type_p(tree type).  This is a static
// method available independently of any vrange object.
//
// To query what a given vrange variant can support, use:
//    irange::supports_p ()
//    frange::supports_p ()
//    etc

However, with the changes I have posted so far, ranges throughout have a 
much finer granularity and are no longer limited to the 2-sub-ranges in 
a value_range.  If you look at IPA dumps now, you'll see the ranges are 
much more refined and are streamed for LTO accordingly.  This is an 
improvement in and of itself.

Aldy
Aldy Hernandez May 22, 2023, 6:43 p.m. UTC | #2
I've adjusted the patch with some minor cleanups that came up when I
implemented the rest of the IPA revamp.

Rested.  OK?

On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> This converts the lattice to store ranges in Value_Range instead of
> value_range (*) to make it type agnostic, and adjust all users
> accordingly.
>
> I think it is a good example on converting from static ranges to more
> general, type agnostic ones.
>
> I've been careful to make sure Value_Range never ends up on GC, since
> it contains an int_range_max and can expand on-demand onto the heap.
> Longer term storage for ranges should be done with vrange_storage, as
> per the previous patch ("Provide an API for ipa_vr").
>
> (*) I do know the Value_Range naming versus value_range is quite
> annoying, but it was a judgement call last release for the eventual
> migration to having "value_range" be a type agnostic range object.  We
> will ultimately rename Value_Range to value_range.
>
> OK for trunk?
>
> gcc/ChangeLog:
>
>         * ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
>         (ipcp_vr_lattice::print): Call dump method.
>         (ipcp_vr_lattice::meet_with): Adjust for m_vr being a
>         Value_Range.
>         (ipcp_vr_lattice::meet_with_1): Make argument a reference.
>         (ipcp_vr_lattice::set_to_bottom): Add type argument.
>         (set_all_contains_variable): Same.
>         (initialize_node_lattices): Pass type when appropriate.
>         (ipa_vr_operation_and_type_effects): Make type agnostic.
>         (ipa_value_range_from_jfunc): Same.
>         (propagate_vr_across_jump_function): Same.
>         (propagate_constants_across_call): Same.
>         * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
>         (evaluate_properties_for_edge): Same.
>         * ipa-prop.cc (ipcp_update_vr): Same.
>         * ipa-prop.h (ipa_value_range_from_jfunc): Same.
>         (ipa_range_set_and_normalize): Same.
> ---
>  gcc/ipa-cp.cc        | 159 +++++++++++++++++++++++--------------------
>  gcc/ipa-fnsummary.cc |  16 ++---
>  gcc/ipa-prop.cc      |   2 +-
>  gcc/ipa-prop.h       |  19 ++----
>  4 files changed, 101 insertions(+), 95 deletions(-)
>
> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> index d4b9d4ac27e..bd5b1da17b2 100644
> --- a/gcc/ipa-cp.cc
> +++ b/gcc/ipa-cp.cc
> @@ -343,20 +343,29 @@ private:
>  class ipcp_vr_lattice
>  {
>  public:
> -  value_range m_vr;
> +  Value_Range m_vr;
>
>    inline bool bottom_p () const;
>    inline bool top_p () const;
> -  inline bool set_to_bottom ();
> -  bool meet_with (const value_range *p_vr);
> +  inline bool set_to_bottom (tree type);
> +  bool meet_with (const vrange &p_vr);
>    bool meet_with (const ipcp_vr_lattice &other);
> -  void init () { gcc_assert (m_vr.undefined_p ()); }
> +  void init (tree type);
>    void print (FILE * f);
>
>  private:
> -  bool meet_with_1 (const value_range *other_vr);
> +  bool meet_with_1 (const vrange &other_vr);
>  };
>
> +inline void
> +ipcp_vr_lattice::init (tree type)
> +{
> +  if (type)
> +    m_vr.set_type (type);
> +
> +  // Otherwise m_vr will default to unsupported_range.
> +}
> +
>  /* Structure containing lattices for a parameter itself and for pieces of
>     aggregates that are passed in the parameter or by a reference in a parameter
>     plus some other useful flags.  */
> @@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
>  void
>  ipcp_vr_lattice::print (FILE * f)
>  {
> -  dump_value_range (f, &m_vr);
> +  m_vr.dump (f);
>  }
>
>  /* Print all ipcp_lattices of all functions to F.  */
> @@ -1016,14 +1025,14 @@ set_agg_lats_contain_variable (class ipcp_param_lattices *plats)
>  bool
>  ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
>  {
> -  return meet_with_1 (&other.m_vr);
> +  return meet_with_1 (other.m_vr);
>  }
>
>  /* Meet the current value of the lattice with value range described by VR
>     lattice.  */
>
>  bool
> -ipcp_vr_lattice::meet_with (const value_range *p_vr)
> +ipcp_vr_lattice::meet_with (const vrange &p_vr)
>  {
>    return meet_with_1 (p_vr);
>  }
> @@ -1032,23 +1041,23 @@ ipcp_vr_lattice::meet_with (const value_range *p_vr)
>     OTHER_VR lattice.  Return TRUE if anything changed.  */
>
>  bool
> -ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
> +ipcp_vr_lattice::meet_with_1 (const vrange &other_vr)
>  {
>    if (bottom_p ())
>      return false;
>
> -  if (other_vr->varying_p ())
> -    return set_to_bottom ();
> +  if (other_vr.varying_p ())
> +    return set_to_bottom (other_vr.type ());
>
>    bool res;
>    if (flag_checking)
>      {
> -      value_range save (m_vr);
> -      res = m_vr.union_ (*other_vr);
> +      Value_Range save (m_vr);
> +      res = m_vr.union_ (other_vr);
>        gcc_assert (res == (m_vr != save));
>      }
>    else
> -    res = m_vr.union_ (*other_vr);
> +    res = m_vr.union_ (other_vr);
>    return res;
>  }
>
> @@ -1073,16 +1082,11 @@ ipcp_vr_lattice::bottom_p () const
>     previously was in a different state.  */
>
>  bool
> -ipcp_vr_lattice::set_to_bottom ()
> +ipcp_vr_lattice::set_to_bottom (tree type)
>  {
>    if (m_vr.varying_p ())
>      return false;
> -  /* ?? We create all sorts of VARYING ranges for floats, structures,
> -     and other types which we cannot handle as ranges.  We should
> -     probably avoid handling them throughout the pass, but it's easier
> -     to create a sensible VARYING here and let the lattice
> -     propagate.  */
> -  m_vr.set_varying (integer_type_node);
> +  m_vr.set_varying (type);
>    return true;
>  }
>
> @@ -1518,14 +1522,14 @@ intersect_argaggs_with (vec<ipa_argagg_value> &elts,
>     return true is any of them has not been marked as such so far.  */
>
>  static inline bool
> -set_all_contains_variable (class ipcp_param_lattices *plats)
> +set_all_contains_variable (class ipcp_param_lattices *plats, tree type)
>  {
>    bool ret;
>    ret = plats->itself.set_contains_variable ();
>    ret |= plats->ctxlat.set_contains_variable ();
>    ret |= set_agg_lats_contain_variable (plats);
>    ret |= plats->bits_lattice.set_to_bottom ();
> -  ret |= plats->m_value_range.set_to_bottom ();
> +  ret |= plats->m_value_range.set_to_bottom (type);
>    return ret;
>  }
>
> @@ -1653,6 +1657,7 @@ initialize_node_lattices (struct cgraph_node *node)
>    for (i = 0; i < ipa_get_param_count (info); i++)
>      {
>        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
> +      tree type = ipa_get_type (info, i);
>        if (disable
>           || !ipa_get_type (info, i)
>           || (pre_modified && (surviving_params.length () <= (unsigned) i
> @@ -1662,14 +1667,14 @@ initialize_node_lattices (struct cgraph_node *node)
>           plats->ctxlat.set_to_bottom ();
>           set_agg_lats_to_bottom (plats);
>           plats->bits_lattice.set_to_bottom ();
> -         plats->m_value_range.m_vr = value_range ();
> -         plats->m_value_range.set_to_bottom ();
> +         plats->m_value_range.init (type);
> +         plats->m_value_range.set_to_bottom (type);
>         }
>        else
>         {
> -         plats->m_value_range.init ();
> +         plats->m_value_range.init (type);
>           if (variable)
> -           set_all_contains_variable (plats);
> +           set_all_contains_variable (plats, type);
>         }
>      }
>
> @@ -1903,8 +1908,8 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
>     the result is a range or an anti-range.  */
>
>  static bool
> -ipa_vr_operation_and_type_effects (value_range *dst_vr,
> -                                  value_range *src_vr,
> +ipa_vr_operation_and_type_effects (vrange &dst_vr,
> +                                  const vrange &src_vr,
>                                    enum tree_code operation,
>                                    tree dst_type, tree src_type)
>  {
> @@ -1912,29 +1917,33 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
>      return false;
>
>    range_op_handler handler (operation, dst_type);
> -  return (handler
> -         && handler.fold_range (*dst_vr, dst_type,
> -                                *src_vr, value_range (dst_type))
> -         && !dst_vr->varying_p ()
> -         && !dst_vr->undefined_p ());
> +  if (!handler)
> +    return false;
> +
> +  Value_Range varying (dst_type);
> +  varying.set_varying (dst_type);
> +
> +  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
> +         && !dst_vr.varying_p ()
> +         && !dst_vr.undefined_p ());
>  }
>
>  /* Determine value_range of JFUNC given that INFO describes the caller node or
>     the one it is inlined to, CS is the call graph edge corresponding to JFUNC
>     and PARM_TYPE of the parameter.  */
>
> -value_range
> -ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
> +void
> +ipa_value_range_from_jfunc (vrange &vr,
> +                           ipa_node_params *info, cgraph_edge *cs,
>                             ipa_jump_func *jfunc, tree parm_type)
>  {
> -  value_range vr;
>    if (jfunc->m_vr)
> -    ipa_vr_operation_and_type_effects (&vr,
> -                                      jfunc->m_vr,
> +    ipa_vr_operation_and_type_effects (vr,
> +                                      *jfunc->m_vr,
>                                        NOP_EXPR, parm_type,
>                                        jfunc->m_vr->type ());
>    if (vr.singleton_p ())
> -    return vr;
> +    return;
>    if (jfunc->type == IPA_JF_PASS_THROUGH)
>      {
>        int idx;
> @@ -1943,33 +1952,34 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>                                            ? cs->caller->inlined_to
>                                            : cs->caller);
>        if (!sum || !sum->m_vr)
> -       return vr;
> +       return;
>
>        idx = ipa_get_jf_pass_through_formal_id (jfunc);
>
>        if (!(*sum->m_vr)[idx].known_p ())
> -       return vr;
> +       return;
>        tree vr_type = ipa_get_type (info, idx);
> -      value_range srcvr;
> +      Value_Range srcvr (vr_type);
>        (*sum->m_vr)[idx].get_vrange (srcvr, vr_type);
>
>        enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
>
>        if (TREE_CODE_CLASS (operation) == tcc_unary)
>         {
> -         value_range res;
> +         Value_Range res (vr_type);
>
> -         if (ipa_vr_operation_and_type_effects (&res,
> -                                                &srcvr,
> +         if (ipa_vr_operation_and_type_effects (res,
> +                                                srcvr,
>                                                  operation, parm_type,
>                                                  vr_type))
>             vr.intersect (res);
>         }
>        else
>         {
> -         value_range op_res, res;
> +         Value_Range op_res (vr_type);
> +         Value_Range res (vr_type);
>           tree op = ipa_get_jf_pass_through_operand (jfunc);
> -         value_range op_vr;
> +         Value_Range op_vr (vr_type);
>           range_op_handler handler (operation, vr_type);
>
>           ipa_range_set_and_normalize (op_vr, op);
> @@ -1979,14 +1989,13 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>               || !handler.fold_range (op_res, vr_type, srcvr, op_vr))
>             op_res.set_varying (vr_type);
>
> -         if (ipa_vr_operation_and_type_effects (&res,
> -                                                &op_res,
> +         if (ipa_vr_operation_and_type_effects (res,
> +                                                op_res,
>                                                  NOP_EXPR, parm_type,
>                                                  vr_type))
>             vr.intersect (res);
>         }
>      }
> -  return vr;
>  }
>
>  /* Determine whether ITEM, jump function for an aggregate part, evaluates to a
> @@ -2739,7 +2748,7 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>    if (!param_type
>        || (!INTEGRAL_TYPE_P (param_type)
>           && !POINTER_TYPE_P (param_type)))
> -    return dest_lat->set_to_bottom ();
> +    return dest_lat->set_to_bottom (param_type);
>
>    if (jfunc->type == IPA_JF_PASS_THROUGH)
>      {
> @@ -2751,12 +2760,12 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>        tree operand_type = ipa_get_type (caller_info, src_idx);
>
>        if (src_lats->m_value_range.bottom_p ())
> -       return dest_lat->set_to_bottom ();
> +       return dest_lat->set_to_bottom (operand_type);
>
> -      value_range vr;
> +      Value_Range vr (operand_type);
>        if (TREE_CODE_CLASS (operation) == tcc_unary)
> -       ipa_vr_operation_and_type_effects (&vr,
> -                                          &src_lats->m_value_range.m_vr,
> +       ipa_vr_operation_and_type_effects (vr,
> +                                          src_lats->m_value_range.m_vr,
>                                            operation, param_type,
>                                            operand_type);
>        /* A crude way to prevent unbounded number of value range updates
> @@ -2765,8 +2774,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>        else if (!ipa_edge_within_scc (cs))
>         {
>           tree op = ipa_get_jf_pass_through_operand (jfunc);
> -         value_range op_vr;
> -         value_range op_res,res;
> +         Value_Range op_vr (TREE_TYPE (op));
> +         Value_Range op_res (operand_type);
>           range_op_handler handler (operation, operand_type);
>
>           ipa_range_set_and_normalize (op_vr, op);
> @@ -2777,8 +2786,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>                                       src_lats->m_value_range.m_vr, op_vr))
>             op_res.set_varying (operand_type);
>
> -         ipa_vr_operation_and_type_effects (&vr,
> -                                            &op_res,
> +         ipa_vr_operation_and_type_effects (vr,
> +                                            op_res,
>                                              NOP_EXPR, param_type,
>                                              operand_type);
>         }
> @@ -2786,14 +2795,14 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>         {
>           if (jfunc->m_vr)
>             {
> -             value_range jvr;
> -             if (ipa_vr_operation_and_type_effects (&jvr, jfunc->m_vr,
> +             Value_Range jvr (param_type);
> +             if (ipa_vr_operation_and_type_effects (jvr, *jfunc->m_vr,
>                                                      NOP_EXPR,
>                                                      param_type,
>                                                      jfunc->m_vr->type ()))
>                 vr.intersect (jvr);
>             }
> -         return dest_lat->meet_with (&vr);
> +         return dest_lat->meet_with (vr);
>         }
>      }
>    else if (jfunc->type == IPA_JF_CONST)
> @@ -2805,20 +2814,19 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>           if (TREE_OVERFLOW_P (val))
>             val = drop_tree_overflow (val);
>
> -         value_range tmpvr (TREE_TYPE (val),
> -                            wi::to_wide (val), wi::to_wide (val));
> -         return dest_lat->meet_with (&tmpvr);
> +         Value_Range tmpvr (val, val);
> +         return dest_lat->meet_with (tmpvr);
>         }
>      }
>
>    value_range vr;
>    if (jfunc->m_vr
> -      && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
> +      && ipa_vr_operation_and_type_effects (vr, *jfunc->m_vr, NOP_EXPR,
>                                             param_type,
>                                             jfunc->m_vr->type ()))
> -    return dest_lat->meet_with (&vr);
> +    return dest_lat->meet_with (vr);
>    else
> -    return dest_lat->set_to_bottom ();
> +    return dest_lat->set_to_bottom (param_type);
>  }
>
>  /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
> @@ -3209,7 +3217,8 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>      {
>        for (i = 0; i < parms_count; i++)
>         ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
> -                                                                i));
> +                                                                i),
> +                                         ipa_get_type (callee_info, i));
>        return ret;
>      }
>    args_count = ipa_get_cs_argument_count (args);
> @@ -3220,7 +3229,8 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>    if (call_passes_through_thunk (cs))
>      {
>        ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
> -                                                              0));
> +                                                              0),
> +                                       ipa_get_type (callee_info, 0));
>        i = 1;
>      }
>    else
> @@ -3234,7 +3244,7 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>
>        dest_plats = ipa_get_parm_lattices (callee_info, i);
>        if (availability == AVAIL_INTERPOSABLE)
> -       ret |= set_all_contains_variable (dest_plats);
> +       ret |= set_all_contains_variable (dest_plats, param_type);
>        else
>         {
>           ret |= propagate_scalar_across_jump_function (cs, jump_func,
> @@ -3251,11 +3261,12 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>             ret |= propagate_vr_across_jump_function (cs, jump_func,
>                                                       dest_plats, param_type);
>           else
> -           ret |= dest_plats->m_value_range.set_to_bottom ();
> +           ret |= dest_plats->m_value_range.set_to_bottom (param_type);
>         }
>      }
>    for (; i < parms_count; i++)
> -    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i));
> +    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i),
> +                                     ipa_get_type (callee_info, i));
>
>    return ret;
>  }
> diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
> index b328bb8ce14..0474af8991e 100644
> --- a/gcc/ipa-fnsummary.cc
> +++ b/gcc/ipa-fnsummary.cc
> @@ -475,7 +475,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
>           && !c->agg_contents
>           && (!val || TREE_CODE (val) != INTEGER_CST))
>         {
> -         value_range vr = avals->m_known_value_ranges[c->operand_num];
> +         Value_Range vr (avals->m_known_value_ranges[c->operand_num]);
>           if (!vr.undefined_p ()
>               && !vr.varying_p ()
>               && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
> @@ -630,8 +630,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>                 || ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>               {
>                 /* Determine if we know constant value of the parameter.  */
> -               tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
> -                                                ipa_get_type (callee_pi, i));
> +               tree type = ipa_get_type (callee_pi, i);
> +               tree cst = ipa_value_from_jfunc (caller_parms_info, jf, type);
>
>                 if (!cst && e->call_stmt
>                     && i < (int)gimple_call_num_args (e->call_stmt))
> @@ -659,10 +659,10 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>                     && vrp_will_run_p (caller)
>                     && ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>                   {
> -                   value_range vr
> -                      = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
> -                                                    ipa_get_type (callee_pi,
> -                                                                  i));
> +                   Value_Range vr (type);
> +
> +                   ipa_value_range_from_jfunc (vr, caller_parms_info, e, jf,
> +                                               ipa_get_type (callee_pi, i));
>                     if (!vr.undefined_p () && !vr.varying_p ())
>                       {
>                         if (!avals->m_known_value_ranges.length ())
> @@ -670,7 +670,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>                             avals->m_known_value_ranges.safe_grow (count, true);
>                             for (int i = 0; i < count; ++i)
>                               new (&avals->m_known_value_ranges[i])
> -                               value_range ();
> +                               Value_Range ();
>                           }
>                         avals->m_known_value_ranges[i] = vr;
>                       }
> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> index 4ace410de49..1a71d7969ea 100644
> --- a/gcc/ipa-prop.cc
> +++ b/gcc/ipa-prop.cc
> @@ -5939,7 +5939,7 @@ ipcp_update_vr (struct cgraph_node *node)
>        if (vr[i].known_p ())
>         {
>           tree type = TREE_TYPE (ddef);
> -         value_range tmp;
> +         Value_Range tmp (type);
>           vr[i].get_vrange (tmp, type);
>
>           if (!tmp.undefined_p () && !tmp.varying_p ())
> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
> index 3b580ebb903..3921e33940d 100644
> --- a/gcc/ipa-prop.h
> +++ b/gcc/ipa-prop.h
> @@ -530,7 +530,7 @@ public:
>    auto_vec<ipa_argagg_value, 32> m_known_aggs;
>
>    /* Vector describing known value ranges of arguments.  */
> -  auto_vec<value_range, 32> m_known_value_ranges;
> +  auto_vec<Value_Range, 32> m_known_value_ranges;
>  };
>
>  inline
> @@ -582,7 +582,7 @@ public:
>    vec<ipa_argagg_value> m_known_aggs = vNULL;
>
>    /* Vector describing known value ranges of arguments.  */
> -  vec<value_range> m_known_value_ranges = vNULL;
> +  vec<Value_Range> m_known_value_ranges = vNULL;
>  };
>
>  inline
> @@ -1194,8 +1194,8 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
>                                                      cgraph_edge *,
>                                                      int,
>                                                      ipa_jump_func *);
> -value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
> -                                       ipa_jump_func *, tree);
> +void ipa_value_range_from_jfunc (vrange &, ipa_node_params *, cgraph_edge *,
> +                                ipa_jump_func *, tree);
>  void ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node,
>                                      ipa_agg_jump_function *agg_jfunc,
>                                      unsigned dst_index,
> @@ -1218,17 +1218,12 @@ void ipa_cp_cc_finalize (void);
>     non-zero.  */
>
>  inline void
> -ipa_range_set_and_normalize (irange &r, tree val)
> +ipa_range_set_and_normalize (vrange &r, tree val)
>  {
> -  if (TREE_CODE (val) == INTEGER_CST)
> -    {
> -      wide_int w = wi::to_wide (val);
> -      r.set (TREE_TYPE (val), w, w);
> -    }
> -  else if (TREE_CODE (val) == ADDR_EXPR)
> +  if (TREE_CODE (val) == ADDR_EXPR)
>      r.set_nonzero (TREE_TYPE (val));
>    else
> -    r.set_varying (TREE_TYPE (val));
> +    r.set (val, val);
>  }
>
>  #endif /* IPA_PROP_H */
> --
> 2.40.0
>
Martin Jambor May 26, 2023, 4:17 p.m. UTC | #3
Hello,

On Mon, May 22 2023, Aldy Hernandez wrote:
> I've adjusted the patch with some minor cleanups that came up when I
> implemented the rest of the IPA revamp.
>
> Rested.  OK?
>
> On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>
>> This converts the lattice to store ranges in Value_Range instead of
>> value_range (*) to make it type agnostic, and adjust all users
>> accordingly.
>>
>> I think it is a good example on converting from static ranges to more
>> general, type agnostic ones.
>>
>> I've been careful to make sure Value_Range never ends up on GC, since
>> it contains an int_range_max and can expand on-demand onto the heap.
>> Longer term storage for ranges should be done with vrange_storage, as
>> per the previous patch ("Provide an API for ipa_vr").
>>
>> (*) I do know the Value_Range naming versus value_range is quite
>> annoying, but it was a judgement call last release for the eventual
>> migration to having "value_range" be a type agnostic range object.  We
>> will ultimately rename Value_Range to value_range.

It is quite confusing for an unsuspecting reader indeed.

>>
>> OK for trunk?

I guess I need to rely on that you know what you are doing :-)
I have seen in other messages that you measure the compile time
effects of your patches, do you look at memory use as well?

I am happy with the overall approach, I just have the following
comments, questions and a few concerns:


>>
>> gcc/ChangeLog:
>>
>>         * ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
>>         (ipcp_vr_lattice::print): Call dump method.
>>         (ipcp_vr_lattice::meet_with): Adjust for m_vr being a
>>         Value_Range.
>>         (ipcp_vr_lattice::meet_with_1): Make argument a reference.
>>         (ipcp_vr_lattice::set_to_bottom): Add type argument.
>>         (set_all_contains_variable): Same.
>>         (initialize_node_lattices): Pass type when appropriate.
>>         (ipa_vr_operation_and_type_effects): Make type agnostic.
>>         (ipa_value_range_from_jfunc): Same.
>>         (propagate_vr_across_jump_function): Same.
>>         (propagate_constants_across_call): Same.
>>         * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
>>         (evaluate_properties_for_edge): Same.
>>         * ipa-prop.cc (ipcp_update_vr): Same.
>>         * ipa-prop.h (ipa_value_range_from_jfunc): Same.
>>         (ipa_range_set_and_normalize): Same.
>> ---
>>  gcc/ipa-cp.cc        | 159 +++++++++++++++++++++++--------------------
>>  gcc/ipa-fnsummary.cc |  16 ++---
>>  gcc/ipa-prop.cc      |   2 +-
>>  gcc/ipa-prop.h       |  19 ++----
>>  4 files changed, 101 insertions(+), 95 deletions(-)
>>
>> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
>> index d4b9d4ac27e..bd5b1da17b2 100644
>> --- a/gcc/ipa-cp.cc
>> +++ b/gcc/ipa-cp.cc
>> @@ -343,20 +343,29 @@ private:
>>  class ipcp_vr_lattice
>>  {
>>  public:
>> -  value_range m_vr;
>> +  Value_Range m_vr;
>>
>>    inline bool bottom_p () const;
>>    inline bool top_p () const;
>> -  inline bool set_to_bottom ();
>> -  bool meet_with (const value_range *p_vr);
>> +  inline bool set_to_bottom (tree type);

Requiring a type when setting a lattice to bottom makes for a weird
interface, can't we set the underlying Value_Range to whatever...

>> +  bool meet_with (const vrange &p_vr);
>>    bool meet_with (const ipcp_vr_lattice &other);
>> -  void init () { gcc_assert (m_vr.undefined_p ()); }
>> +  void init (tree type);
>>    void print (FILE * f);
>>
>>  private:
>> -  bool meet_with_1 (const value_range *other_vr);
>> +  bool meet_with_1 (const vrange &other_vr);
>>  };
>>
>> +inline void
>> +ipcp_vr_lattice::init (tree type)
>> +{
>> +  if (type)
>> +    m_vr.set_type (type);
>> +
>> +  // Otherwise m_vr will default to unsupported_range.

...this does?

All users of the lattice check it for not being bottom first, so it
should be safe.

If it is not possible for some reason, then I guess we should add a bool
flag to ipcp_vr_lattice instead, rather than looking up types of
unusable lattices.  ipcp_vr_lattices don't live for long.

>> +}
>> +
>>  /* Structure containing lattices for a parameter itself and for pieces of
>>     aggregates that are passed in the parameter or by a reference in a parameter
>>     plus some other useful flags.  */
>> @@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
>>  void
>>  ipcp_vr_lattice::print (FILE * f)
>>  {
>> -  dump_value_range (f, &m_vr);
>> +  m_vr.dump (f);
>>  }
>>
>>  /* Print all ipcp_lattices of all functions to F.  */
>> @@ -1016,14 +1025,14 @@ set_agg_lats_contain_variable (class ipcp_param_lattices *plats)
>>  bool
>>  ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
>>  {
>> -  return meet_with_1 (&other.m_vr);
>> +  return meet_with_1 (other.m_vr);
>>  }
>>
>>  /* Meet the current value of the lattice with value range described by VR
>>     lattice.  */
>>
>>  bool
>> -ipcp_vr_lattice::meet_with (const value_range *p_vr)
>> +ipcp_vr_lattice::meet_with (const vrange &p_vr)
>>  {
>>    return meet_with_1 (p_vr);
>>  }
>> @@ -1032,23 +1041,23 @@ ipcp_vr_lattice::meet_with (const value_range *p_vr)
>>     OTHER_VR lattice.  Return TRUE if anything changed.  */
>>
>>  bool
>> -ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
>> +ipcp_vr_lattice::meet_with_1 (const vrange &other_vr)
>>  {
>>    if (bottom_p ())
>>      return false;
>>
>> -  if (other_vr->varying_p ())
>> -    return set_to_bottom ();
>> +  if (other_vr.varying_p ())
>> +    return set_to_bottom (other_vr.type ());
>>
>>    bool res;
>>    if (flag_checking)
>>      {
>> -      value_range save (m_vr);
>> -      res = m_vr.union_ (*other_vr);
>> +      Value_Range save (m_vr);
>> +      res = m_vr.union_ (other_vr);
>>        gcc_assert (res == (m_vr != save));
>>      }
>>    else
>> -    res = m_vr.union_ (*other_vr);
>> +    res = m_vr.union_ (other_vr);
>>    return res;
>>  }
>>
>> @@ -1073,16 +1082,11 @@ ipcp_vr_lattice::bottom_p () const
>>     previously was in a different state.  */
>>
>>  bool
>> -ipcp_vr_lattice::set_to_bottom ()
>> +ipcp_vr_lattice::set_to_bottom (tree type)
>>  {
>>    if (m_vr.varying_p ())
>>      return false;
>> -  /* ?? We create all sorts of VARYING ranges for floats, structures,
>> -     and other types which we cannot handle as ranges.  We should
>> -     probably avoid handling them throughout the pass, but it's easier
>> -     to create a sensible VARYING here and let the lattice
>> -     propagate.  */
>> -  m_vr.set_varying (integer_type_node);
>> +  m_vr.set_varying (type);
>>    return true;
>>  }
>>
>> @@ -1518,14 +1522,14 @@ intersect_argaggs_with (vec<ipa_argagg_value> &elts,
>>     return true is any of them has not been marked as such so far.  */
>>
>>  static inline bool
>> -set_all_contains_variable (class ipcp_param_lattices *plats)
>> +set_all_contains_variable (class ipcp_param_lattices *plats, tree type)
>>  {

...then functions like these would not need the extra parameter either.

>>    bool ret;
>>    ret = plats->itself.set_contains_variable ();
>>    ret |= plats->ctxlat.set_contains_variable ();
>>    ret |= set_agg_lats_contain_variable (plats);
>>    ret |= plats->bits_lattice.set_to_bottom ();
>> -  ret |= plats->m_value_range.set_to_bottom ();
>> +  ret |= plats->m_value_range.set_to_bottom (type);
>>    return ret;
>>  }
>>
>> @@ -1653,6 +1657,7 @@ initialize_node_lattices (struct cgraph_node *node)
>>    for (i = 0; i < ipa_get_param_count (info); i++)
>>      {
>>        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
>> +      tree type = ipa_get_type (info, i);
>>        if (disable
>>           || !ipa_get_type (info, i)
>>           || (pre_modified && (surviving_params.length () <= (unsigned) i
>> @@ -1662,14 +1667,14 @@ initialize_node_lattices (struct cgraph_node *node)
>>           plats->ctxlat.set_to_bottom ();
>>           set_agg_lats_to_bottom (plats);
>>           plats->bits_lattice.set_to_bottom ();
>> -         plats->m_value_range.m_vr = value_range ();
>> -         plats->m_value_range.set_to_bottom ();
>> +         plats->m_value_range.init (type);
>> +         plats->m_value_range.set_to_bottom (type);
>>         }
>>        else
>>         {
>> -         plats->m_value_range.init ();
>> +         plats->m_value_range.init (type);
>>           if (variable)
>> -           set_all_contains_variable (plats);
>> +           set_all_contains_variable (plats, type);
>>         }
>>      }
>>
>> @@ -1903,8 +1908,8 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
>>     the result is a range or an anti-range.  */
>>
>>  static bool
>> -ipa_vr_operation_and_type_effects (value_range *dst_vr,
>> -                                  value_range *src_vr,
>> +ipa_vr_operation_and_type_effects (vrange &dst_vr,
>> +                                  const vrange &src_vr,
>>                                    enum tree_code operation,
>>                                    tree dst_type, tree src_type)
>>  {
>> @@ -1912,29 +1917,33 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
>>      return false;
>>
>>    range_op_handler handler (operation, dst_type);
>> -  return (handler
>> -         && handler.fold_range (*dst_vr, dst_type,
>> -                                *src_vr, value_range (dst_type))
>> -         && !dst_vr->varying_p ()
>> -         && !dst_vr->undefined_p ());
>> +  if (!handler)
>> +    return false;
>> +
>> +  Value_Range varying (dst_type);
>> +  varying.set_varying (dst_type);
>> +
>> +  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
>> +         && !dst_vr.varying_p ()
>> +         && !dst_vr.undefined_p ());
>>  }
>>
>>  /* Determine value_range of JFUNC given that INFO describes the caller node or
>>     the one it is inlined to, CS is the call graph edge corresponding to JFUNC
>>     and PARM_TYPE of the parameter.  */
>>
>> -value_range
>> -ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>> +void
>> +ipa_value_range_from_jfunc (vrange &vr,
>> +                           ipa_node_params *info, cgraph_edge *cs,
>>                             ipa_jump_func *jfunc, tree parm_type)

I assume that you decided to return the value in a parameter passed by
reference instead of in return value for a good reason but then can we
at least...


>>  {
>> -  value_range vr;
>>    if (jfunc->m_vr)
>> -    ipa_vr_operation_and_type_effects (&vr,
>> -                                      jfunc->m_vr,
>> +    ipa_vr_operation_and_type_effects (vr,
>> +                                      *jfunc->m_vr,
>>                                        NOP_EXPR, parm_type,
>>                                        jfunc->m_vr->type ());
>>    if (vr.singleton_p ())
>> -    return vr;
>> +    return;

...make sure that whenever the function intends to return a varying VR
it actually does so instead of not touching it at all?

>>    if (jfunc->type == IPA_JF_PASS_THROUGH)
>>      {
>>        int idx;
>> @@ -1943,33 +1952,34 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>                                            ? cs->caller->inlined_to
>>                                            : cs->caller);
>>        if (!sum || !sum->m_vr)
>> -       return vr;
>> +       return;

Likewise.

>>
>>        idx = ipa_get_jf_pass_through_formal_id (jfunc);
>>
>>        if (!(*sum->m_vr)[idx].known_p ())
>> -       return vr;
>> +       return;

Likewise.

>>        tree vr_type = ipa_get_type (info, idx);
>> -      value_range srcvr;
>> +      Value_Range srcvr (vr_type);
>>        (*sum->m_vr)[idx].get_vrange (srcvr, vr_type);
>>
>>        enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
>>
>>        if (TREE_CODE_CLASS (operation) == tcc_unary)
>>         {
>> -         value_range res;
>> +         Value_Range res (vr_type);
>>
>> -         if (ipa_vr_operation_and_type_effects (&res,
>> -                                                &srcvr,
>> +         if (ipa_vr_operation_and_type_effects (res,
>> +                                                srcvr,
>>                                                  operation, parm_type,
>>                                                  vr_type))
>>             vr.intersect (res);

Here we also now make assumptions about the state of vr which we did not
before, should we perhaps assign res into vr instead?

>>         }
>>        else
>>         {
>> -         value_range op_res, res;
>> +         Value_Range op_res (vr_type);
>> +         Value_Range res (vr_type);
>>           tree op = ipa_get_jf_pass_through_operand (jfunc);
>> -         value_range op_vr;
>> +         Value_Range op_vr (vr_type);
>>           range_op_handler handler (operation, vr_type);
>>
>>           ipa_range_set_and_normalize (op_vr, op);
>> @@ -1979,14 +1989,13 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>               || !handler.fold_range (op_res, vr_type, srcvr, op_vr))
>>             op_res.set_varying (vr_type);
>>
>> -         if (ipa_vr_operation_and_type_effects (&res,
>> -                                                &op_res,
>> +         if (ipa_vr_operation_and_type_effects (res,
>> +                                                op_res,
>>                                                  NOP_EXPR, parm_type,
>>                                                  vr_type))
>>             vr.intersect (res);

Likewise.

>>         }
>>      }
>> -  return vr;
>>  }
>>
>>  /* Determine whether ITEM, jump function for an aggregate part, evaluates to a
>> @@ -2739,7 +2748,7 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>    if (!param_type
>>        || (!INTEGRAL_TYPE_P (param_type)
>>           && !POINTER_TYPE_P (param_type)))
>> -    return dest_lat->set_to_bottom ();
>> +    return dest_lat->set_to_bottom (param_type);
>>
>>    if (jfunc->type == IPA_JF_PASS_THROUGH)
>>      {
>> @@ -2751,12 +2760,12 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>        tree operand_type = ipa_get_type (caller_info, src_idx);
>>
>>        if (src_lats->m_value_range.bottom_p ())
>> -       return dest_lat->set_to_bottom ();
>> +       return dest_lat->set_to_bottom (operand_type);
>>
>> -      value_range vr;
>> +      Value_Range vr (operand_type);
>>        if (TREE_CODE_CLASS (operation) == tcc_unary)
>> -       ipa_vr_operation_and_type_effects (&vr,
>> -                                          &src_lats->m_value_range.m_vr,
>> +       ipa_vr_operation_and_type_effects (vr,
>> +                                          src_lats->m_value_range.m_vr,
>>                                            operation, param_type,
>>                                            operand_type);
>>        /* A crude way to prevent unbounded number of value range updates
>> @@ -2765,8 +2774,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>        else if (!ipa_edge_within_scc (cs))
>>         {
>>           tree op = ipa_get_jf_pass_through_operand (jfunc);
>> -         value_range op_vr;
>> -         value_range op_res,res;
>> +         Value_Range op_vr (TREE_TYPE (op));
>> +         Value_Range op_res (operand_type);
>>           range_op_handler handler (operation, operand_type);
>>
>>           ipa_range_set_and_normalize (op_vr, op);
>> @@ -2777,8 +2786,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>                                       src_lats->m_value_range.m_vr, op_vr))
>>             op_res.set_varying (operand_type);
>>
>> -         ipa_vr_operation_and_type_effects (&vr,
>> -                                            &op_res,
>> +         ipa_vr_operation_and_type_effects (vr,
>> +                                            op_res,
>>                                              NOP_EXPR, param_type,
>>                                              operand_type);
>>         }
>> @@ -2786,14 +2795,14 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>         {
>>           if (jfunc->m_vr)
>>             {
>> -             value_range jvr;
>> -             if (ipa_vr_operation_and_type_effects (&jvr, jfunc->m_vr,
>> +             Value_Range jvr (param_type);
>> +             if (ipa_vr_operation_and_type_effects (jvr, *jfunc->m_vr,
>>                                                      NOP_EXPR,
>>                                                      param_type,
>>                                                      jfunc->m_vr->type ()))
>>                 vr.intersect (jvr);
>>             }
>> -         return dest_lat->meet_with (&vr);
>> +         return dest_lat->meet_with (vr);
>>         }
>>      }
>>    else if (jfunc->type == IPA_JF_CONST)
>> @@ -2805,20 +2814,19 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>           if (TREE_OVERFLOW_P (val))
>>             val = drop_tree_overflow (val);
>>
>> -         value_range tmpvr (TREE_TYPE (val),
>> -                            wi::to_wide (val), wi::to_wide (val));
>> -         return dest_lat->meet_with (&tmpvr);
>> +         Value_Range tmpvr (val, val);
>> +         return dest_lat->meet_with (tmpvr);
>>         }
>>      }
>>
>>    value_range vr;
>>    if (jfunc->m_vr
>> -      && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
>> +      && ipa_vr_operation_and_type_effects (vr, *jfunc->m_vr, NOP_EXPR,
>>                                             param_type,
>>                                             jfunc->m_vr->type ()))
>> -    return dest_lat->meet_with (&vr);
>> +    return dest_lat->meet_with (vr);
>>    else
>> -    return dest_lat->set_to_bottom ();
>> +    return dest_lat->set_to_bottom (param_type);
>>  }
>>
>>  /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
>> @@ -3209,7 +3217,8 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>      {
>>        for (i = 0; i < parms_count; i++)
>>         ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
>> -                                                                i));
>> +                                                                i),
>> +                                         ipa_get_type (callee_info, i));

I have complained about it above but this another example where making
ipcp_vr_lattice::set_to_bottom not require a type which is not really
needed could even save a tiny bit of compile time.

>>        return ret;
>>      }
>>    args_count = ipa_get_cs_argument_count (args);
>> @@ -3220,7 +3229,8 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>    if (call_passes_through_thunk (cs))
>>      {
>>        ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
>> -                                                              0));
>> +                                                              0),
>> +                                       ipa_get_type (callee_info, 0));
>>        i = 1;
>>      }
>>    else
>> @@ -3234,7 +3244,7 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>
>>        dest_plats = ipa_get_parm_lattices (callee_info, i);
>>        if (availability == AVAIL_INTERPOSABLE)
>> -       ret |= set_all_contains_variable (dest_plats);
>> +       ret |= set_all_contains_variable (dest_plats, param_type);
>>        else
>>         {
>>           ret |= propagate_scalar_across_jump_function (cs, jump_func,
>> @@ -3251,11 +3261,12 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>             ret |= propagate_vr_across_jump_function (cs, jump_func,
>>                                                       dest_plats, param_type);
>>           else
>> -           ret |= dest_plats->m_value_range.set_to_bottom ();
>> +           ret |= dest_plats->m_value_range.set_to_bottom (param_type);
>>         }
>>      }
>>    for (; i < parms_count; i++)
>> -    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i));
>> +    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i),
>> +                                     ipa_get_type (callee_info, i));
>>
>>    return ret;
>>  }
>> diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
>> index b328bb8ce14..0474af8991e 100644
>> --- a/gcc/ipa-fnsummary.cc
>> +++ b/gcc/ipa-fnsummary.cc
>> @@ -475,7 +475,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
>>           && !c->agg_contents
>>           && (!val || TREE_CODE (val) != INTEGER_CST))
>>         {
>> -         value_range vr = avals->m_known_value_ranges[c->operand_num];
>> +         Value_Range vr (avals->m_known_value_ranges[c->operand_num]);
>>           if (!vr.undefined_p ()
>>               && !vr.varying_p ()
>>               && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
>> @@ -630,8 +630,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>                 || ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>>               {
>>                 /* Determine if we know constant value of the parameter.  */
>> -               tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
>> -                                                ipa_get_type (callee_pi, i));
>> +               tree type = ipa_get_type (callee_pi, i);
>> +               tree cst = ipa_value_from_jfunc (caller_parms_info, jf, type);
>>
>>                 if (!cst && e->call_stmt
>>                     && i < (int)gimple_call_num_args (e->call_stmt))
>> @@ -659,10 +659,10 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>                     && vrp_will_run_p (caller)
>>                     && ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>>                   {
>> -                   value_range vr
>> -                      = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
>> -                                                    ipa_get_type (callee_pi,
>> -                                                                  i));
>> +                   Value_Range vr (type);
>> +
>> +                   ipa_value_range_from_jfunc (vr, caller_parms_info, e, jf,
>> +                                               ipa_get_type (callee_pi, i));

I guess that the ipa_get_type call can also be replaced with "type" now.

>>                     if (!vr.undefined_p () && !vr.varying_p ())
>>                       {
>>                         if (!avals->m_known_value_ranges.length ())
>> @@ -670,7 +670,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>                             avals->m_known_value_ranges.safe_grow (count, true);
>>                             for (int i = 0; i < count; ++i)
>>                               new (&avals->m_known_value_ranges[i])
>> -                               value_range ();
>> +                               Value_Range ();
>>                           }
>>                         avals->m_known_value_ranges[i] = vr;
>>                       }

Thanks for working on this and sorry that it takes me so long to review.

Martin
Aldy Hernandez June 6, 2023, 12:43 p.m. UTC | #4
My apologies for the delay.  I was on vacation.

On 5/26/23 18:17, Martin Jambor wrote:
> Hello,
> 
> On Mon, May 22 2023, Aldy Hernandez wrote:
>> I've adjusted the patch with some minor cleanups that came up when I
>> implemented the rest of the IPA revamp.
>>
>> Rested.  OK?
>>
>> On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>>
>>> This converts the lattice to store ranges in Value_Range instead of
>>> value_range (*) to make it type agnostic, and adjust all users
>>> accordingly.
>>>
>>> I think it is a good example on converting from static ranges to more
>>> general, type agnostic ones.
>>>
>>> I've been careful to make sure Value_Range never ends up on GC, since
>>> it contains an int_range_max and can expand on-demand onto the heap.
>>> Longer term storage for ranges should be done with vrange_storage, as
>>> per the previous patch ("Provide an API for ipa_vr").
>>>
>>> (*) I do know the Value_Range naming versus value_range is quite
>>> annoying, but it was a judgement call last release for the eventual
>>> migration to having "value_range" be a type agnostic range object.  We
>>> will ultimately rename Value_Range to value_range.
> 
> It is quite confusing for an unsuspecting reader indeed.
> 
>>>
>>> OK for trunk?
> 
> I guess I need to rely on that you know what you are doing :-)
> I have seen in other messages that you measure the compile time
> effects of your patches, do you look at memory use as well?

Before going in depth into the rest of your review (thanks BTW), let's 
address memory usage.

To be honest, I didn't measure memory, but only because I had a pretty 
good inkling that it wouldn't make a difference, since vrange_storage is 
designed to take less space than value_range which you were using.  But 
you're right, I should've measured it.

First value_range is a derived-POD so it has a vtable pointer in there. 
vrange_storage does not.

Second, vrange_storage only uses the minimum number of bytes to 
represent the integers in the range.  vrange_storage uses a 
trailing_wide_int type mechanism to store the minimum amount of HWIs for 
a range.   See irange_storage::set_irange().

value_range is a typedef for int_range<2>.  Storing this in GC, which 
IPA currently does, takes 432 bytes.  I will be removing the GTY markers 
for irange, to keep anyone from even trying.

On the other hand, storing this same range in GC memory with 
vrange_storage takes 35 bytes for a [5, 10] range:

   unsigned prec = TYPE_PRECISION (integer_type_node);
   wide_int min = wi::shwi (5, prec);
   wide_int max = wi::shwi (10, prec);
   int_range<2> r (integer_type_node, min, max);
   vrange_storage *p = ggc_alloc_vrange_storage (r);

Breaking on irange_storage::alloc() you can see the size of the 
allocated object is 35 bytes.  This is far less than 432 bytes in trunk 
(due to the wide_int penalty in this release), but even so is comparable 
to GCC12 which took 32 bytes.  Note that GCC12 was using trees, so those 
32 bytes were deceptive, since there was another level of indirection 
involved for the actual HWIs.

Anywhoo... I tried comparing GCC 12 to current mainline plus these 
patches, but it was a royal PITA, because so much has changed, not just 
in the ranger world, but in the rest of the compiler.

However, comparing trunk against my patches is a total wash, even 
considering that IPA will now store a gazillion more ranges.

For measuring I built with --enable-gather-detailed-mem-stats and 
compared the "Total Allocated:" lines from -fmem-report for the 
aggregate of all .ii files in a bootstrap:

Before:
Total allocated: 73360474112.0 bytes

After:
Total allocated: 73354182656.0 bytes

So we use 0.00858% less memory.

To be honest, this is an unfair comparison because trunk IPA is 
streaming out the full value_range (wide_int's and all which changed in 
this release), but with these patches:

a) We don't stream out vtable pointer.
b) Even if the number of sub-ranges can be larger, we only store the 
bare minimum, and we're capped at 255 sub-ranges (which I've never seen 
in the wild).

I think we're good, but if this ever becomes a problem, the constructor 
for ipa_vr could just be tweaked to squish things down before allocating:

ipa_vr::ipa_vr (const vrange &v)
   : m_type (v.type ())
{
   if (is_a <irange> (v))
     {
       int_range<10> squish (as_a <irange> (v));
       m_storage = ggc_alloc_vrange_storage (squish);
     }
   else
     m_storage = ggc_alloc_vrange_storage (v);
}

I'll address the rest of your comments in follow-up mails.
Aldy
Aldy Hernandez June 7, 2023, 10:18 a.m. UTC | #5
On 5/26/23 18:17, Martin Jambor wrote:
> Hello,
> 
> On Mon, May 22 2023, Aldy Hernandez wrote:
>> I've adjusted the patch with some minor cleanups that came up when I
>> implemented the rest of the IPA revamp.
>>
>> Rested.  OK?
>>
>> On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>>
>>> This converts the lattice to store ranges in Value_Range instead of
>>> value_range (*) to make it type agnostic, and adjust all users
>>> accordingly.
>>>
>>> I think it is a good example on converting from static ranges to more
>>> general, type agnostic ones.
>>>
>>> I've been careful to make sure Value_Range never ends up on GC, since
>>> it contains an int_range_max and can expand on-demand onto the heap.
>>> Longer term storage for ranges should be done with vrange_storage, as
>>> per the previous patch ("Provide an API for ipa_vr").
>>>
>>> (*) I do know the Value_Range naming versus value_range is quite
>>> annoying, but it was a judgement call last release for the eventual
>>> migration to having "value_range" be a type agnostic range object.  We
>>> will ultimately rename Value_Range to value_range.
> 
> It is quite confusing for an unsuspecting reader indeed.
> 
>>>
>>> OK for trunk?
> 
> I guess I need to rely on that you know what you are doing :-)

I wouldn't go that far ;-).

> I have seen in other messages that you measure the compile time
> effects of your patches, do you look at memory use as well?

As per my message yesterday, the memory usage seems reasonable.

> 
> I am happy with the overall approach, I just have the following
> comments, questions and a few concerns:
> 
> 
>>>
>>> gcc/ChangeLog:
>>>
>>>          * ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
>>>          (ipcp_vr_lattice::print): Call dump method.
>>>          (ipcp_vr_lattice::meet_with): Adjust for m_vr being a
>>>          Value_Range.
>>>          (ipcp_vr_lattice::meet_with_1): Make argument a reference.
>>>          (ipcp_vr_lattice::set_to_bottom): Add type argument.
>>>          (set_all_contains_variable): Same.
>>>          (initialize_node_lattices): Pass type when appropriate.
>>>          (ipa_vr_operation_and_type_effects): Make type agnostic.
>>>          (ipa_value_range_from_jfunc): Same.
>>>          (propagate_vr_across_jump_function): Same.
>>>          (propagate_constants_across_call): Same.
>>>          * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
>>>          (evaluate_properties_for_edge): Same.
>>>          * ipa-prop.cc (ipcp_update_vr): Same.
>>>          * ipa-prop.h (ipa_value_range_from_jfunc): Same.
>>>          (ipa_range_set_and_normalize): Same.
>>> ---
>>>   gcc/ipa-cp.cc        | 159 +++++++++++++++++++++++--------------------
>>>   gcc/ipa-fnsummary.cc |  16 ++---
>>>   gcc/ipa-prop.cc      |   2 +-
>>>   gcc/ipa-prop.h       |  19 ++----
>>>   4 files changed, 101 insertions(+), 95 deletions(-)
>>>
>>> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
>>> index d4b9d4ac27e..bd5b1da17b2 100644
>>> --- a/gcc/ipa-cp.cc
>>> +++ b/gcc/ipa-cp.cc
>>> @@ -343,20 +343,29 @@ private:
>>>   class ipcp_vr_lattice
>>>   {
>>>   public:
>>> -  value_range m_vr;
>>> +  Value_Range m_vr;
>>>
>>>     inline bool bottom_p () const;
>>>     inline bool top_p () const;
>>> -  inline bool set_to_bottom ();
>>> -  bool meet_with (const value_range *p_vr);
>>> +  inline bool set_to_bottom (tree type);
> 
> Requiring a type when setting a lattice to bottom makes for a weird
> interface, can't we set the underlying Value_Range to whatever... >
>>> +  bool meet_with (const vrange &p_vr);
>>>     bool meet_with (const ipcp_vr_lattice &other);
>>> -  void init () { gcc_assert (m_vr.undefined_p ()); }
>>> +  void init (tree type);
>>>     void print (FILE * f);
>>>
>>>   private:
>>> -  bool meet_with_1 (const value_range *other_vr);
>>> +  bool meet_with_1 (const vrange &other_vr);
>>>   };
>>>
>>> +inline void
>>> +ipcp_vr_lattice::init (tree type)
>>> +{
>>> +  if (type)
>>> +    m_vr.set_type (type);
>>> +
>>> +  // Otherwise m_vr will default to unsupported_range.
> 
> ...this does?
> 
> All users of the lattice check it for not being bottom first, so it
> should be safe.
> 
> If it is not possible for some reason, then I guess we should add a bool
> flag to ipcp_vr_lattice instead, rather than looking up types of
> unusable lattices.  ipcp_vr_lattices don't live for long.

The type was my least favorite part of this work.  And yes, your 
suggestion would work.  I have tweaked the patch to force a VARYING for 
an unsupported range which seems to do the trick.  It looks much 
cleaner.  Thanks.

> 
>>> +}
>>> +
>>>   /* Structure containing lattices for a parameter itself and for pieces of
>>>      aggregates that are passed in the parameter or by a reference in a parameter
>>>      plus some other useful flags.  */
>>> @@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
>>>   void
>>>   ipcp_vr_lattice::print (FILE * f)
>>>   {
>>> -  dump_value_range (f, &m_vr);
>>> +  m_vr.dump (f);
>>>   }
>>>
>>>   /* Print all ipcp_lattices of all functions to F.  */
>>> @@ -1016,14 +1025,14 @@ set_agg_lats_contain_variable (class ipcp_param_lattices *plats)
>>>   bool
>>>   ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
>>>   {
>>> -  return meet_with_1 (&other.m_vr);
>>> +  return meet_with_1 (other.m_vr);
>>>   }
>>>
>>>   /* Meet the current value of the lattice with value range described by VR
>>>      lattice.  */
>>>
>>>   bool
>>> -ipcp_vr_lattice::meet_with (const value_range *p_vr)
>>> +ipcp_vr_lattice::meet_with (const vrange &p_vr)
>>>   {
>>>     return meet_with_1 (p_vr);
>>>   }
>>> @@ -1032,23 +1041,23 @@ ipcp_vr_lattice::meet_with (const value_range *p_vr)
>>>      OTHER_VR lattice.  Return TRUE if anything changed.  */
>>>
>>>   bool
>>> -ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
>>> +ipcp_vr_lattice::meet_with_1 (const vrange &other_vr)
>>>   {
>>>     if (bottom_p ())
>>>       return false;
>>>
>>> -  if (other_vr->varying_p ())
>>> -    return set_to_bottom ();
>>> +  if (other_vr.varying_p ())
>>> +    return set_to_bottom (other_vr.type ());
>>>
>>>     bool res;
>>>     if (flag_checking)
>>>       {
>>> -      value_range save (m_vr);
>>> -      res = m_vr.union_ (*other_vr);
>>> +      Value_Range save (m_vr);
>>> +      res = m_vr.union_ (other_vr);
>>>         gcc_assert (res == (m_vr != save));
>>>       }
>>>     else
>>> -    res = m_vr.union_ (*other_vr);
>>> +    res = m_vr.union_ (other_vr);
>>>     return res;
>>>   }
>>>
>>> @@ -1073,16 +1082,11 @@ ipcp_vr_lattice::bottom_p () const
>>>      previously was in a different state.  */
>>>
>>>   bool
>>> -ipcp_vr_lattice::set_to_bottom ()
>>> +ipcp_vr_lattice::set_to_bottom (tree type)
>>>   {
>>>     if (m_vr.varying_p ())
>>>       return false;
>>> -  /* ?? We create all sorts of VARYING ranges for floats, structures,
>>> -     and other types which we cannot handle as ranges.  We should
>>> -     probably avoid handling them throughout the pass, but it's easier
>>> -     to create a sensible VARYING here and let the lattice
>>> -     propagate.  */
>>> -  m_vr.set_varying (integer_type_node);
>>> +  m_vr.set_varying (type);
>>>     return true;
>>>   }
>>>
>>> @@ -1518,14 +1522,14 @@ intersect_argaggs_with (vec<ipa_argagg_value> &elts,
>>>      return true is any of them has not been marked as such so far.  */
>>>
>>>   static inline bool
>>> -set_all_contains_variable (class ipcp_param_lattices *plats)
>>> +set_all_contains_variable (class ipcp_param_lattices *plats, tree type)
>>>   {
> 
> ...then functions like these would not need the extra parameter either.
> 
>>>     bool ret;
>>>     ret = plats->itself.set_contains_variable ();
>>>     ret |= plats->ctxlat.set_contains_variable ();
>>>     ret |= set_agg_lats_contain_variable (plats);
>>>     ret |= plats->bits_lattice.set_to_bottom ();
>>> -  ret |= plats->m_value_range.set_to_bottom ();
>>> +  ret |= plats->m_value_range.set_to_bottom (type);
>>>     return ret;
>>>   }
>>>
>>> @@ -1653,6 +1657,7 @@ initialize_node_lattices (struct cgraph_node *node)
>>>     for (i = 0; i < ipa_get_param_count (info); i++)
>>>       {
>>>         ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
>>> +      tree type = ipa_get_type (info, i);
>>>         if (disable
>>>            || !ipa_get_type (info, i)
>>>            || (pre_modified && (surviving_params.length () <= (unsigned) i
>>> @@ -1662,14 +1667,14 @@ initialize_node_lattices (struct cgraph_node *node)
>>>            plats->ctxlat.set_to_bottom ();
>>>            set_agg_lats_to_bottom (plats);
>>>            plats->bits_lattice.set_to_bottom ();
>>> -         plats->m_value_range.m_vr = value_range ();
>>> -         plats->m_value_range.set_to_bottom ();
>>> +         plats->m_value_range.init (type);
>>> +         plats->m_value_range.set_to_bottom (type);
>>>          }
>>>         else
>>>          {
>>> -         plats->m_value_range.init ();
>>> +         plats->m_value_range.init (type);
>>>            if (variable)
>>> -           set_all_contains_variable (plats);
>>> +           set_all_contains_variable (plats, type);
>>>          }
>>>       }
>>>
>>> @@ -1903,8 +1908,8 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
>>>      the result is a range or an anti-range.  */
>>>
>>>   static bool
>>> -ipa_vr_operation_and_type_effects (value_range *dst_vr,
>>> -                                  value_range *src_vr,
>>> +ipa_vr_operation_and_type_effects (vrange &dst_vr,
>>> +                                  const vrange &src_vr,
>>>                                     enum tree_code operation,
>>>                                     tree dst_type, tree src_type)
>>>   {
>>> @@ -1912,29 +1917,33 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
>>>       return false;
>>>
>>>     range_op_handler handler (operation, dst_type);
>>> -  return (handler
>>> -         && handler.fold_range (*dst_vr, dst_type,
>>> -                                *src_vr, value_range (dst_type))
>>> -         && !dst_vr->varying_p ()
>>> -         && !dst_vr->undefined_p ());
>>> +  if (!handler)
>>> +    return false;
>>> +
>>> +  Value_Range varying (dst_type);
>>> +  varying.set_varying (dst_type);
>>> +
>>> +  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
>>> +         && !dst_vr.varying_p ()
>>> +         && !dst_vr.undefined_p ());
>>>   }
>>>
>>>   /* Determine value_range of JFUNC given that INFO describes the caller node or
>>>      the one it is inlined to, CS is the call graph edge corresponding to JFUNC
>>>      and PARM_TYPE of the parameter.  */
>>>
>>> -value_range
>>> -ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>> +void
>>> +ipa_value_range_from_jfunc (vrange &vr,
>>> +                           ipa_node_params *info, cgraph_edge *cs,
>>>                              ipa_jump_func *jfunc, tree parm_type)
> 
> I assume that you decided to return the value in a parameter passed by
> reference instead of in return value for a good reason but then can we
> at least...

vrange is an abstract type, plus it can be any size (int_range<3> has 3 
sub-ranges, legacy value_range has 2 sub-ranges, frange is a totally 
different object, etc).  Throughout all of ranger, returning a range is 
done by passing by reference.  This has the added benefit that sometimes 
we can set a return range by twiddling a few bits (foo.set_undefined()) 
instead of having to copy a full range back and forth.

> 
> 
>>>   {
>>> -  value_range vr;
>>>     if (jfunc->m_vr)
>>> -    ipa_vr_operation_and_type_effects (&vr,
>>> -                                      jfunc->m_vr,
>>> +    ipa_vr_operation_and_type_effects (vr,
>>> +                                      *jfunc->m_vr,
>>>                                         NOP_EXPR, parm_type,
>>>                                         jfunc->m_vr->type ());
>>>     if (vr.singleton_p ())
>>> -    return vr;
>>> +    return;
> 
> ...make sure that whenever the function intends to return a varying VR
> it actually does so instead of not touching it at all?

Good catch.  The original "value_range vr;" definition would default vr 
to UNDEFINED, which would no longer happen with my patch.  I have added 
a vr.set_undefined() at the original definition site, which would make 
everything work.

> 
>>>     if (jfunc->type == IPA_JF_PASS_THROUGH)
>>>       {
>>>         int idx;
>>> @@ -1943,33 +1952,34 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>>                                             ? cs->caller->inlined_to
>>>                                             : cs->caller);
>>>         if (!sum || !sum->m_vr)
>>> -       return vr;
>>> +       return;
> 
> Likewise.
> 
>>>
>>>         idx = ipa_get_jf_pass_through_formal_id (jfunc);
>>>
>>>         if (!(*sum->m_vr)[idx].known_p ())
>>> -       return vr;
>>> +       return;
> 
> Likewise.
> 
>>>         tree vr_type = ipa_get_type (info, idx);
>>> -      value_range srcvr;
>>> +      Value_Range srcvr (vr_type);
>>>         (*sum->m_vr)[idx].get_vrange (srcvr, vr_type);
>>>
>>>         enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
>>>
>>>         if (TREE_CODE_CLASS (operation) == tcc_unary)
>>>          {
>>> -         value_range res;
>>> +         Value_Range res (vr_type);
>>>
>>> -         if (ipa_vr_operation_and_type_effects (&res,
>>> -                                                &srcvr,
>>> +         if (ipa_vr_operation_and_type_effects (res,
>>> +                                                srcvr,
>>>                                                   operation, parm_type,
>>>                                                   vr_type))
>>>              vr.intersect (res);
> 
> Here we also now make assumptions about the state of vr which we did not
> before, should we perhaps assign res into vr instead?

With the initialization of vr to UNDEFINED, this should be OK as both of 
these initialize "res" to UNDEFINED:

 >>> -         value_range res;
 >>> +         Value_Range res (vr_type);

So vr and res both have the same default as before.

> 
>>>          }
>>>         else
>>>          {
>>> -         value_range op_res, res;
>>> +         Value_Range op_res (vr_type);
>>> +         Value_Range res (vr_type);
>>>            tree op = ipa_get_jf_pass_through_operand (jfunc);
>>> -         value_range op_vr;
>>> +         Value_Range op_vr (vr_type);
>>>            range_op_handler handler (operation, vr_type);
>>>
>>>            ipa_range_set_and_normalize (op_vr, op);
>>> @@ -1979,14 +1989,13 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>>                || !handler.fold_range (op_res, vr_type, srcvr, op_vr))
>>>              op_res.set_varying (vr_type);
>>>
>>> -         if (ipa_vr_operation_and_type_effects (&res,
>>> -                                                &op_res,
>>> +         if (ipa_vr_operation_and_type_effects (res,
>>> +                                                op_res,
>>>                                                   NOP_EXPR, parm_type,
>>>                                                   vr_type))
>>>              vr.intersect (res);
> 
> Likewise.
> 
>>>          }
>>>       }
>>> -  return vr;
>>>   }
>>>
>>>   /* Determine whether ITEM, jump function for an aggregate part, evaluates to a
>>> @@ -2739,7 +2748,7 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>>     if (!param_type
>>>         || (!INTEGRAL_TYPE_P (param_type)
>>>            && !POINTER_TYPE_P (param_type)))
>>> -    return dest_lat->set_to_bottom ();
>>> +    return dest_lat->set_to_bottom (param_type);
>>>
>>>     if (jfunc->type == IPA_JF_PASS_THROUGH)
>>>       {
>>> @@ -2751,12 +2760,12 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>>         tree operand_type = ipa_get_type (caller_info, src_idx);
>>>
>>>         if (src_lats->m_value_range.bottom_p ())
>>> -       return dest_lat->set_to_bottom ();
>>> +       return dest_lat->set_to_bottom (operand_type);
>>>
>>> -      value_range vr;
>>> +      Value_Range vr (operand_type);
>>>         if (TREE_CODE_CLASS (operation) == tcc_unary)
>>> -       ipa_vr_operation_and_type_effects (&vr,
>>> -                                          &src_lats->m_value_range.m_vr,
>>> +       ipa_vr_operation_and_type_effects (vr,
>>> +                                          src_lats->m_value_range.m_vr,
>>>                                             operation, param_type,
>>>                                             operand_type);
>>>         /* A crude way to prevent unbounded number of value range updates
>>> @@ -2765,8 +2774,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>>         else if (!ipa_edge_within_scc (cs))
>>>          {
>>>            tree op = ipa_get_jf_pass_through_operand (jfunc);
>>> -         value_range op_vr;
>>> -         value_range op_res,res;
>>> +         Value_Range op_vr (TREE_TYPE (op));
>>> +         Value_Range op_res (operand_type);
>>>            range_op_handler handler (operation, operand_type);
>>>
>>>            ipa_range_set_and_normalize (op_vr, op);
>>> @@ -2777,8 +2786,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>>                                        src_lats->m_value_range.m_vr, op_vr))
>>>              op_res.set_varying (operand_type);
>>>
>>> -         ipa_vr_operation_and_type_effects (&vr,
>>> -                                            &op_res,
>>> +         ipa_vr_operation_and_type_effects (vr,
>>> +                                            op_res,
>>>                                               NOP_EXPR, param_type,
>>>                                               operand_type);
>>>          }
>>> @@ -2786,14 +2795,14 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>>          {
>>>            if (jfunc->m_vr)
>>>              {
>>> -             value_range jvr;
>>> -             if (ipa_vr_operation_and_type_effects (&jvr, jfunc->m_vr,
>>> +             Value_Range jvr (param_type);
>>> +             if (ipa_vr_operation_and_type_effects (jvr, *jfunc->m_vr,
>>>                                                       NOP_EXPR,
>>>                                                       param_type,
>>>                                                       jfunc->m_vr->type ()))
>>>                  vr.intersect (jvr);
>>>              }
>>> -         return dest_lat->meet_with (&vr);
>>> +         return dest_lat->meet_with (vr);
>>>          }
>>>       }
>>>     else if (jfunc->type == IPA_JF_CONST)
>>> @@ -2805,20 +2814,19 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>>            if (TREE_OVERFLOW_P (val))
>>>              val = drop_tree_overflow (val);
>>>
>>> -         value_range tmpvr (TREE_TYPE (val),
>>> -                            wi::to_wide (val), wi::to_wide (val));
>>> -         return dest_lat->meet_with (&tmpvr);
>>> +         Value_Range tmpvr (val, val);
>>> +         return dest_lat->meet_with (tmpvr);
>>>          }
>>>       }
>>>
>>>     value_range vr;
>>>     if (jfunc->m_vr
>>> -      && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
>>> +      && ipa_vr_operation_and_type_effects (vr, *jfunc->m_vr, NOP_EXPR,
>>>                                              param_type,
>>>                                              jfunc->m_vr->type ()))
>>> -    return dest_lat->meet_with (&vr);
>>> +    return dest_lat->meet_with (vr);
>>>     else
>>> -    return dest_lat->set_to_bottom ();
>>> +    return dest_lat->set_to_bottom (param_type);
>>>   }
>>>
>>>   /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
>>> @@ -3209,7 +3217,8 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>>       {
>>>         for (i = 0; i < parms_count; i++)
>>>          ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
>>> -                                                                i));
>>> +                                                                i),
>>> +                                         ipa_get_type (callee_info, i));
> 
> I have complained about it above but this another example where making
> ipcp_vr_lattice::set_to_bottom not require a type which is not really
> needed could even save a tiny bit of compile time.
> 
>>>         return ret;
>>>       }
>>>     args_count = ipa_get_cs_argument_count (args);
>>> @@ -3220,7 +3229,8 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>>     if (call_passes_through_thunk (cs))
>>>       {
>>>         ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
>>> -                                                              0));
>>> +                                                              0),
>>> +                                       ipa_get_type (callee_info, 0));
>>>         i = 1;
>>>       }
>>>     else
>>> @@ -3234,7 +3244,7 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>>
>>>         dest_plats = ipa_get_parm_lattices (callee_info, i);
>>>         if (availability == AVAIL_INTERPOSABLE)
>>> -       ret |= set_all_contains_variable (dest_plats);
>>> +       ret |= set_all_contains_variable (dest_plats, param_type);
>>>         else
>>>          {
>>>            ret |= propagate_scalar_across_jump_function (cs, jump_func,
>>> @@ -3251,11 +3261,12 @@ propagate_constants_across_call (struct cgraph_edge *cs)
>>>              ret |= propagate_vr_across_jump_function (cs, jump_func,
>>>                                                        dest_plats, param_type);
>>>            else
>>> -           ret |= dest_plats->m_value_range.set_to_bottom ();
>>> +           ret |= dest_plats->m_value_range.set_to_bottom (param_type);
>>>          }
>>>       }
>>>     for (; i < parms_count; i++)
>>> -    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i));
>>> +    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i),
>>> +                                     ipa_get_type (callee_info, i));
>>>
>>>     return ret;
>>>   }
>>> diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
>>> index b328bb8ce14..0474af8991e 100644
>>> --- a/gcc/ipa-fnsummary.cc
>>> +++ b/gcc/ipa-fnsummary.cc
>>> @@ -475,7 +475,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
>>>            && !c->agg_contents
>>>            && (!val || TREE_CODE (val) != INTEGER_CST))
>>>          {
>>> -         value_range vr = avals->m_known_value_ranges[c->operand_num];
>>> +         Value_Range vr (avals->m_known_value_ranges[c->operand_num]);
>>>            if (!vr.undefined_p ()
>>>                && !vr.varying_p ()
>>>                && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
>>> @@ -630,8 +630,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>>                  || ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>>>                {
>>>                  /* Determine if we know constant value of the parameter.  */
>>> -               tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
>>> -                                                ipa_get_type (callee_pi, i));
>>> +               tree type = ipa_get_type (callee_pi, i);
>>> +               tree cst = ipa_value_from_jfunc (caller_parms_info, jf, type);
>>>
>>>                  if (!cst && e->call_stmt
>>>                      && i < (int)gimple_call_num_args (e->call_stmt))
>>> @@ -659,10 +659,10 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>>                      && vrp_will_run_p (caller)
>>>                      && ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>>>                    {
>>> -                   value_range vr
>>> -                      = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
>>> -                                                    ipa_get_type (callee_pi,
>>> -                                                                  i));
>>> +                   Value_Range vr (type);
>>> +
>>> +                   ipa_value_range_from_jfunc (vr, caller_parms_info, e, jf,
>>> +                                               ipa_get_type (callee_pi, i));
> 
> I guess that the ipa_get_type call can also be replaced with "type" now.

Done.

> 
>>>                      if (!vr.undefined_p () && !vr.varying_p ())
>>>                        {
>>>                          if (!avals->m_known_value_ranges.length ())
>>> @@ -670,7 +670,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>>                              avals->m_known_value_ranges.safe_grow (count, true);
>>>                              for (int i = 0; i < count; ++i)
>>>                                new (&avals->m_known_value_ranges[i])
>>> -                               value_range ();
>>> +                               Value_Range ();
>>>                            }
>>>                          avals->m_known_value_ranges[i] = vr;
>>>                        }
> 
> Thanks for working on this and sorry that it takes me so long to review.
> 
> Martin
> 

How's this?

Aldy
Martin Jambor June 10, 2023, 8:49 a.m. UTC | #6
Hi,

thanks for dealing with my requests.

On Wed, Jun 07 2023, Aldy Hernandez wrote:
> On 5/26/23 18:17, Martin Jambor wrote:
>> Hello,
>> 
>> On Mon, May 22 2023, Aldy Hernandez wrote:
>>> I've adjusted the patch with some minor cleanups that came up when I
>>> implemented the rest of the IPA revamp.
>>>
>>> Rested.  OK?
>>>
>>> On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>>>
>>>> This converts the lattice to store ranges in Value_Range instead of
>>>> value_range (*) to make it type agnostic, and adjust all users
>>>> accordingly.
>>>>
>>>> I think it is a good example on converting from static ranges to more
>>>> general, type agnostic ones.
>>>>
>>>> I've been careful to make sure Value_Range never ends up on GC, since
>>>> it contains an int_range_max and can expand on-demand onto the heap.
>>>> Longer term storage for ranges should be done with vrange_storage, as
>>>> per the previous patch ("Provide an API for ipa_vr").
>>>>
>>>> (*) I do know the Value_Range naming versus value_range is quite
>>>> annoying, but it was a judgement call last release for the eventual
>>>> migration to having "value_range" be a type agnostic range object.  We
>>>> will ultimately rename Value_Range to value_range.

[...]

>>>> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
>>>> index d4b9d4ac27e..bd5b1da17b2 100644
>>>> --- a/gcc/ipa-cp.cc
>>>> +++ b/gcc/ipa-cp.cc
>>>> @@ -343,20 +343,29 @@ private:
>>>>   class ipcp_vr_lattice
>>>>   {
>>>>   public:
>>>> -  value_range m_vr;
>>>> +  Value_Range m_vr;
>>>>
>>>>     inline bool bottom_p () const;
>>>>     inline bool top_p () const;
>>>> -  inline bool set_to_bottom ();
>>>> -  bool meet_with (const value_range *p_vr);
>>>> +  inline bool set_to_bottom (tree type);
>> 
>> Requiring a type when setting a lattice to bottom makes for a weird
>> interface, can't we set the underlying Value_Range to whatever... >
>>>> +  bool meet_with (const vrange &p_vr);
>>>>     bool meet_with (const ipcp_vr_lattice &other);
>>>> -  void init () { gcc_assert (m_vr.undefined_p ()); }
>>>> +  void init (tree type);
>>>>     void print (FILE * f);
>>>>
>>>>   private:
>>>> -  bool meet_with_1 (const value_range *other_vr);
>>>> +  bool meet_with_1 (const vrange &other_vr);
>>>>   };
>>>>
>>>> +inline void
>>>> +ipcp_vr_lattice::init (tree type)
>>>> +{
>>>> +  if (type)
>>>> +    m_vr.set_type (type);
>>>> +
>>>> +  // Otherwise m_vr will default to unsupported_range.
>> 
>> ...this does?
>> 
>> All users of the lattice check it for not being bottom first, so it
>> should be safe.
>> 
>> If it is not possible for some reason, then I guess we should add a bool
>> flag to ipcp_vr_lattice instead, rather than looking up types of
>> unusable lattices.  ipcp_vr_lattices don't live for long.
>
> The type was my least favorite part of this work.  And yes, your 
> suggestion would work.  I have tweaked the patch to force a VARYING for 
> an unsupported range which seems to do the trick.  It looks much 
> cleaner.  Thanks.

This version is much better indeed.

[...]

>>>> @@ -1912,29 +1917,33 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
>>>>       return false;
>>>>
>>>>     range_op_handler handler (operation, dst_type);
>>>> -  return (handler
>>>> -         && handler.fold_range (*dst_vr, dst_type,
>>>> -                                *src_vr, value_range (dst_type))
>>>> -         && !dst_vr->varying_p ()
>>>> -         && !dst_vr->undefined_p ());
>>>> +  if (!handler)
>>>> +    return false;
>>>> +
>>>> +  Value_Range varying (dst_type);
>>>> +  varying.set_varying (dst_type);
>>>> +
>>>> +  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
>>>> +         && !dst_vr.varying_p ()
>>>> +         && !dst_vr.undefined_p ());
>>>>   }
>>>>
>>>>   /* Determine value_range of JFUNC given that INFO describes the caller node or
>>>>      the one it is inlined to, CS is the call graph edge corresponding to JFUNC
>>>>      and PARM_TYPE of the parameter.  */
>>>>
>>>> -value_range
>>>> -ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>>> +void
>>>> +ipa_value_range_from_jfunc (vrange &vr,
>>>> +                           ipa_node_params *info, cgraph_edge *cs,
>>>>                              ipa_jump_func *jfunc, tree parm_type)
>> 
>> I assume that you decided to return the value in a parameter passed by
>> reference instead of in return value for a good reason but then can we
>> at least...
>
> vrange is an abstract type, plus it can be any size (int_range<3> has 3 
> sub-ranges, legacy value_range has 2 sub-ranges, frange is a totally 
> different object, etc).  Throughout all of ranger, returning a range is 
> done by passing by reference.  This has the added benefit that sometimes 
> we can set a return range by twiddling a few bits (foo.set_undefined()) 
> instead of having to copy a full range back and forth.
>

I see, thanks.

[...]

>
> How's this?

One minor observation below...

>
> Aldy
> From 2fd0ae47aa094675a02763e72d7bb7404ed9334b Mon Sep 17 00:00:00 2001
> From: Aldy Hernandez <aldyh@redhat.com>
> Date: Wed, 17 May 2023 11:29:34 +0200
> Subject: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.
>
> This converts the lattice to store ranges in Value_Range instead of
> value_range (*) to make it type agnostic, and adjust all users
> accordingly.
>
> I've been careful to make sure Value_Range never ends up on GC, since
> it contains an int_range_max and can expand on-demand onto the heap.
> Longer term storage for ranges should be done with vrange_storage, as
> per the previous patch ("Provide an API for ipa_vr").
>
> gcc/ChangeLog:
>
> 	* ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
> 	(ipcp_vr_lattice::print): Call dump method.
> 	(ipcp_vr_lattice::meet_with): Adjust for m_vr being a
>         Value_Range.
> 	(ipcp_vr_lattice::meet_with_1): Make argument a reference.
> 	(ipcp_vr_lattice::set_to_bottom): Set varying for an unsupported
> 	range.
> 	(initialize_node_lattices): Pass type when appropriate.
> 	(ipa_vr_operation_and_type_effects): Make type agnostic.
> 	(ipa_value_range_from_jfunc): Same.
> 	(propagate_vr_across_jump_function): Same.
> 	* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
> 	(evaluate_properties_for_edge): Same.
> 	* ipa-prop.cc (ipa_vr::get_vrange): Same.
> 	(ipcp_update_vr): Same.
> 	* ipa-prop.h (ipa_value_range_from_jfunc): Same.
> 	(ipa_range_set_and_normalize): Same.
> ---
>  gcc/ipa-cp.cc        | 148 ++++++++++++++++++++++++-------------------
>  gcc/ipa-fnsummary.cc |  15 ++---
>  gcc/ipa-prop.cc      |   5 +-
>  gcc/ipa-prop.h       |  21 +++---
>  4 files changed, 101 insertions(+), 88 deletions(-)
>
> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> index 0f37bb5e336..d77b9eab249 100644
> --- a/gcc/ipa-cp.cc
> +++ b/gcc/ipa-cp.cc
> @@ -343,20 +343,29 @@ private:
>  class ipcp_vr_lattice
>  {
>  public:
> -  value_range m_vr;
> +  Value_Range m_vr;
>  
>    inline bool bottom_p () const;
>    inline bool top_p () const;
>    inline bool set_to_bottom ();
> -  bool meet_with (const value_range *p_vr);
> +  bool meet_with (const vrange &p_vr);
>    bool meet_with (const ipcp_vr_lattice &other);
> -  void init () { gcc_assert (m_vr.undefined_p ()); }
> +  void init (tree type);
>    void print (FILE * f);
>  
>  private:
> -  bool meet_with_1 (const value_range *other_vr);
> +  bool meet_with_1 (const vrange &other_vr);
>  };
>  
> +inline void
> +ipcp_vr_lattice::init (tree type)
> +{
> +  if (type)
> +    m_vr.set_type (type);
> +
> +  // Otherwise m_vr will default to unsupported_range.
> +}
> +
>  /* Structure containing lattices for a parameter itself and for pieces of
>     aggregates that are passed in the parameter or by a reference in a parameter
>     plus some other useful flags.  */
> @@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
>  void
>  ipcp_vr_lattice::print (FILE * f)
>  {
> -  dump_value_range (f, &m_vr);
> +  m_vr.dump (f);
>  }
>  
>  /* Print all ipcp_lattices of all functions to F.  */
> @@ -1016,39 +1025,39 @@ set_agg_lats_contain_variable (class ipcp_param_lattices *plats)
>  bool
>  ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
>  {
> -  return meet_with_1 (&other.m_vr);
> +  return meet_with_1 (other.m_vr);
>  }
>  
> -/* Meet the current value of the lattice with value range described by VR
> -   lattice.  */
> +/* Meet the current value of the lattice with the range described by
> +   P_VR.  */
>  
>  bool
> -ipcp_vr_lattice::meet_with (const value_range *p_vr)
> +ipcp_vr_lattice::meet_with (const vrange &p_vr)
>  {
>    return meet_with_1 (p_vr);
>  }
>  
> -/* Meet the current value of the lattice with value range described by
> -   OTHER_VR lattice.  Return TRUE if anything changed.  */
> +/* Meet the current value of the lattice with the range described by
> +   OTHER_VR.  Return TRUE if anything changed.  */
>  
>  bool
> -ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
> +ipcp_vr_lattice::meet_with_1 (const vrange &other_vr)
>  {
>    if (bottom_p ())
>      return false;
>  
> -  if (other_vr->varying_p ())
> +  if (other_vr.varying_p ())
>      return set_to_bottom ();
>  
>    bool res;
>    if (flag_checking)
>      {
> -      value_range save (m_vr);
> -      res = m_vr.union_ (*other_vr);
> +      Value_Range save (m_vr);
> +      res = m_vr.union_ (other_vr);
>        gcc_assert (res == (m_vr != save));
>      }
>    else
> -    res = m_vr.union_ (*other_vr);
> +    res = m_vr.union_ (other_vr);
>    return res;
>  }
>  
> @@ -1077,12 +1086,15 @@ ipcp_vr_lattice::set_to_bottom ()
>  {
>    if (m_vr.varying_p ())
>      return false;
> -  /* ?? We create all sorts of VARYING ranges for floats, structures,
> -     and other types which we cannot handle as ranges.  We should
> -     probably avoid handling them throughout the pass, but it's easier
> -     to create a sensible VARYING here and let the lattice
> -     propagate.  */
> -  m_vr.set_varying (integer_type_node);
> +
> +  /* Setting an unsupported type here forces the temporary to default
> +     to unsupported_range, which can handle VARYING/DEFINED ranges,
> +     but nothing else (union, intersect, etc).  This allows us to set
> +     bottoms on any ranges, and is safe as all users of the lattice
> +     check for bottom first.  */
> +  m_vr.set_type (void_type_node);
> +  m_vr.set_varying (void_type_node);
> +
>    return true;
>  }
>  
> @@ -1653,6 +1665,7 @@ initialize_node_lattices (struct cgraph_node *node)
>    for (i = 0; i < ipa_get_param_count (info); i++)
>      {
>        ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
> +      tree type = ipa_get_type (info, i);
>        if (disable
>  	  || !ipa_get_type (info, i)
>  	  || (pre_modified && (surviving_params.length () <= (unsigned) i
> @@ -1662,12 +1675,12 @@ initialize_node_lattices (struct cgraph_node *node)
>  	  plats->ctxlat.set_to_bottom ();
>  	  set_agg_lats_to_bottom (plats);
>  	  plats->bits_lattice.set_to_bottom ();
> -	  plats->m_value_range.m_vr = value_range ();
> +	  plats->m_value_range.init (type);
>  	  plats->m_value_range.set_to_bottom ();

This sequence of init(type) followed by set_to_bottom looks a little
superfluous, is it?

>  	}
>        else
>  	{
> -	  plats->m_value_range.init ();
> +	  plats->m_value_range.init (type);

Same here.

But the patch is OK either way.

Thanks again,

Martin


>  	  if (variable)
>  	    set_all_contains_variable (plats);
>  	}
> @@ -1900,11 +1913,11 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
>  
>  /* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
>     DST_TYPE on value range in SRC_VR and store it to DST_VR.  Return true if
> -   the result is a range or an anti-range.  */
> +   the result is a range that is not VARYING nor UNDEFINED.  */
>  
>  static bool
> -ipa_vr_operation_and_type_effects (value_range *dst_vr,
> -				   value_range *src_vr,
> +ipa_vr_operation_and_type_effects (vrange &dst_vr,
> +				   const vrange &src_vr,
>  				   enum tree_code operation,
>  				   tree dst_type, tree src_type)
>  {
> @@ -1912,29 +1925,35 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
>      return false;
>  
>    range_op_handler handler (operation, dst_type);
> -  return (handler
> -	  && handler.fold_range (*dst_vr, dst_type,
> -				 *src_vr, value_range (dst_type))
> -	  && !dst_vr->varying_p ()
> -	  && !dst_vr->undefined_p ());
> +  if (!handler)
> +    return false;
> +
> +  Value_Range varying (dst_type);
> +  varying.set_varying (dst_type);
> +
> +  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
> +	  && !dst_vr.varying_p ()
> +	  && !dst_vr.undefined_p ());
>  }
>  
>  /* Determine range of JFUNC given that INFO describes the caller node or
>     the one it is inlined to, CS is the call graph edge corresponding to JFUNC
>     and PARM_TYPE of the parameter.  */
>  
> -value_range
> -ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
> +void
> +ipa_value_range_from_jfunc (vrange &vr,
> +			    ipa_node_params *info, cgraph_edge *cs,
>  			    ipa_jump_func *jfunc, tree parm_type)
>  {
> -  value_range vr;
> +  vr.set_undefined ();
> +
>    if (jfunc->m_vr)
> -    ipa_vr_operation_and_type_effects (&vr,
> -				       jfunc->m_vr,
> +    ipa_vr_operation_and_type_effects (vr,
> +				       *jfunc->m_vr,
>  				       NOP_EXPR, parm_type,
>  				       jfunc->m_vr->type ());
>    if (vr.singleton_p ())
> -    return vr;
> +    return;
>    if (jfunc->type == IPA_JF_PASS_THROUGH)
>      {
>        int idx;
> @@ -1943,33 +1962,34 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>  					   ? cs->caller->inlined_to
>  					   : cs->caller);
>        if (!sum || !sum->m_vr)
> -	return vr;
> +	return;
>  
>        idx = ipa_get_jf_pass_through_formal_id (jfunc);
>  
>        if (!(*sum->m_vr)[idx].known_p ())
> -	return vr;
> +	return;
>        tree vr_type = ipa_get_type (info, idx);
> -      value_range srcvr;
> +      Value_Range srcvr;
>        (*sum->m_vr)[idx].get_vrange (srcvr);
>  
>        enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
>  
>        if (TREE_CODE_CLASS (operation) == tcc_unary)
>  	{
> -	  value_range res;
> +	  Value_Range res (vr_type);
>  
> -	  if (ipa_vr_operation_and_type_effects (&res,
> -						 &srcvr,
> +	  if (ipa_vr_operation_and_type_effects (res,
> +						 srcvr,
>  						 operation, parm_type,
>  						 vr_type))
>  	    vr.intersect (res);
>  	}
>        else
>  	{
> -	  value_range op_res, res;
> +	  Value_Range op_res (vr_type);
> +	  Value_Range res (vr_type);
>  	  tree op = ipa_get_jf_pass_through_operand (jfunc);
> -	  value_range op_vr;
> +	  Value_Range op_vr (vr_type);
>  	  range_op_handler handler (operation, vr_type);
>  
>  	  ipa_range_set_and_normalize (op_vr, op);
> @@ -1979,14 +1999,13 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>  	      || !handler.fold_range (op_res, vr_type, srcvr, op_vr))
>  	    op_res.set_varying (vr_type);
>  
> -	  if (ipa_vr_operation_and_type_effects (&res,
> -						 &op_res,
> +	  if (ipa_vr_operation_and_type_effects (res,
> +						 op_res,
>  						 NOP_EXPR, parm_type,
>  						 vr_type))
>  	    vr.intersect (res);
>  	}
>      }
> -  return vr;
>  }
>  
>  /* Determine whether ITEM, jump function for an aggregate part, evaluates to a
> @@ -2753,10 +2772,10 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>        if (src_lats->m_value_range.bottom_p ())
>  	return dest_lat->set_to_bottom ();
>  
> -      value_range vr;
> +      Value_Range vr (operand_type);
>        if (TREE_CODE_CLASS (operation) == tcc_unary)
> -	ipa_vr_operation_and_type_effects (&vr,
> -					   &src_lats->m_value_range.m_vr,
> +	ipa_vr_operation_and_type_effects (vr,
> +					   src_lats->m_value_range.m_vr,
>  					   operation, param_type,
>  					   operand_type);
>        /* A crude way to prevent unbounded number of value range updates
> @@ -2765,8 +2784,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>        else if (!ipa_edge_within_scc (cs))
>  	{
>  	  tree op = ipa_get_jf_pass_through_operand (jfunc);
> -	  value_range op_vr;
> -	  value_range op_res,res;
> +	  Value_Range op_vr (TREE_TYPE (op));
> +	  Value_Range op_res (operand_type);
>  	  range_op_handler handler (operation, operand_type);
>  
>  	  ipa_range_set_and_normalize (op_vr, op);
> @@ -2777,8 +2796,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>  				      src_lats->m_value_range.m_vr, op_vr))
>  	    op_res.set_varying (operand_type);
>  
> -	  ipa_vr_operation_and_type_effects (&vr,
> -					     &op_res,
> +	  ipa_vr_operation_and_type_effects (vr,
> +					     op_res,
>  					     NOP_EXPR, param_type,
>  					     operand_type);
>  	}
> @@ -2786,14 +2805,14 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>  	{
>  	  if (jfunc->m_vr)
>  	    {
> -	      value_range jvr;
> -	      if (ipa_vr_operation_and_type_effects (&jvr, jfunc->m_vr,
> +	      Value_Range jvr (param_type);
> +	      if (ipa_vr_operation_and_type_effects (jvr, *jfunc->m_vr,
>  						     NOP_EXPR,
>  						     param_type,
>  						     jfunc->m_vr->type ()))
>  		vr.intersect (jvr);
>  	    }
> -	  return dest_lat->meet_with (&vr);
> +	  return dest_lat->meet_with (vr);
>  	}
>      }
>    else if (jfunc->type == IPA_JF_CONST)
> @@ -2805,18 +2824,17 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>  	  if (TREE_OVERFLOW_P (val))
>  	    val = drop_tree_overflow (val);
>  
> -	  value_range tmpvr (TREE_TYPE (val),
> -			     wi::to_wide (val), wi::to_wide (val));
> -	  return dest_lat->meet_with (&tmpvr);
> +	  Value_Range tmpvr (val, val);
> +	  return dest_lat->meet_with (tmpvr);
>  	}
>      }
>  
> -  value_range vr;
> +  Value_Range vr (param_type);
>    if (jfunc->m_vr
> -      && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
> +      && ipa_vr_operation_and_type_effects (vr, *jfunc->m_vr, NOP_EXPR,
>  					    param_type,
>  					    jfunc->m_vr->type ()))
> -    return dest_lat->meet_with (&vr);
> +    return dest_lat->meet_with (vr);
>    else
>      return dest_lat->set_to_bottom ();
>  }
> diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
> index b328bb8ce14..cf416202920 100644
> --- a/gcc/ipa-fnsummary.cc
> +++ b/gcc/ipa-fnsummary.cc
> @@ -475,7 +475,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
>  	  && !c->agg_contents
>  	  && (!val || TREE_CODE (val) != INTEGER_CST))
>  	{
> -	  value_range vr = avals->m_known_value_ranges[c->operand_num];
> +	  Value_Range vr (avals->m_known_value_ranges[c->operand_num]);
>  	  if (!vr.undefined_p ()
>  	      && !vr.varying_p ()
>  	      && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
> @@ -630,8 +630,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>  		|| ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>  	      {
>  		/* Determine if we know constant value of the parameter.  */
> -		tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
> -						 ipa_get_type (callee_pi, i));
> +		tree type = ipa_get_type (callee_pi, i);
> +		tree cst = ipa_value_from_jfunc (caller_parms_info, jf, type);
>  
>  		if (!cst && e->call_stmt
>  		    && i < (int)gimple_call_num_args (e->call_stmt))
> @@ -659,10 +659,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>  		    && vrp_will_run_p (caller)
>  		    && ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>  		  {
> -		    value_range vr
> -		       = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
> -						     ipa_get_type (callee_pi,
> -								   i));
> +		    Value_Range vr (type);
> +
> +		    ipa_value_range_from_jfunc (vr, caller_parms_info, e, jf, type);
>  		    if (!vr.undefined_p () && !vr.varying_p ())
>  		      {
>  			if (!avals->m_known_value_ranges.length ())
> @@ -670,7 +669,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>  			    avals->m_known_value_ranges.safe_grow (count, true);
>  			    for (int i = 0; i < count; ++i)
>  			      new (&avals->m_known_value_ranges[i])
> -				value_range ();
> +				Value_Range ();
>  			  }
>  			avals->m_known_value_ranges[i] = vr;
>  		      }
> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> index ab6de9f10da..bbfe0f8aa45 100644
> --- a/gcc/ipa-prop.cc
> +++ b/gcc/ipa-prop.cc
> @@ -198,8 +198,9 @@ ipa_vr::equal_p (const vrange &r) const
>  }
>  
>  void
> -ipa_vr::get_vrange (vrange &r) const
> +ipa_vr::get_vrange (Value_Range &r) const
>  {
> +  r.set_type (m_type);
>    m_storage->get_vrange (r, m_type);
>  }
>  
> @@ -5963,7 +5964,7 @@ ipcp_update_vr (struct cgraph_node *node)
>  
>        if (vr[i].known_p ())
>  	{
> -	  value_range tmp;
> +	  Value_Range tmp;
>  	  vr[i].get_vrange (tmp);
>  
>  	  if (!tmp.undefined_p () && !tmp.varying_p ())
> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
> index f306f8a377e..3a591a8f44d 100644
> --- a/gcc/ipa-prop.h
> +++ b/gcc/ipa-prop.h
> @@ -314,7 +314,7 @@ public:
>    void set_unknown ();
>    bool known_p () const { return m_storage != NULL; }
>    tree type () const { return m_type; }
> -  void get_vrange (vrange &) const;
> +  void get_vrange (Value_Range &) const;
>    bool equal_p (const vrange &) const;
>    const vrange_storage *storage () const { return m_storage; }
>    void streamer_read (lto_input_block *, data_in *);
> @@ -530,7 +530,7 @@ public:
>    auto_vec<ipa_argagg_value, 32> m_known_aggs;
>  
>    /* Vector describing known value ranges of arguments.  */
> -  auto_vec<value_range, 32> m_known_value_ranges;
> +  auto_vec<Value_Range, 32> m_known_value_ranges;
>  };
>  
>  inline
> @@ -582,7 +582,7 @@ public:
>    vec<ipa_argagg_value> m_known_aggs = vNULL;
>  
>    /* Vector describing known value ranges of arguments.  */
> -  vec<value_range> m_known_value_ranges = vNULL;
> +  vec<Value_Range> m_known_value_ranges = vNULL;
>  };
>  
>  inline
> @@ -1194,8 +1194,8 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
>  						     cgraph_edge *,
>  						     int,
>  						     ipa_jump_func *);
> -value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
> -					ipa_jump_func *, tree);
> +void ipa_value_range_from_jfunc (vrange &, ipa_node_params *, cgraph_edge *,
> +				 ipa_jump_func *, tree);
>  void ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node,
>  				     ipa_agg_jump_function *agg_jfunc,
>  				     unsigned dst_index,
> @@ -1218,17 +1218,12 @@ void ipa_cp_cc_finalize (void);
>     non-zero.  */
>  
>  inline void
> -ipa_range_set_and_normalize (irange &r, tree val)
> +ipa_range_set_and_normalize (vrange &r, tree val)
>  {
> -  if (TREE_CODE (val) == INTEGER_CST)
> -    {
> -      wide_int w = wi::to_wide (val);
> -      r.set (TREE_TYPE (val), w, w);
> -    }
> -  else if (TREE_CODE (val) == ADDR_EXPR)
> +  if (TREE_CODE (val) == ADDR_EXPR)
>      r.set_nonzero (TREE_TYPE (val));
>    else
> -    r.set_varying (TREE_TYPE (val));
> +    r.set (val, val);
>  }
>  
>  #endif /* IPA_PROP_H */
> -- 
> 2.40.1
Aldy Hernandez June 10, 2023, 8:24 p.m. UTC | #7
On 6/10/23 10:49, Martin Jambor wrote:
> Hi,
> 
> thanks for dealing with my requests.
> 
> On Wed, Jun 07 2023, Aldy Hernandez wrote:
>> On 5/26/23 18:17, Martin Jambor wrote:
>>> Hello,
>>>
>>> On Mon, May 22 2023, Aldy Hernandez wrote:
>>>> I've adjusted the patch with some minor cleanups that came up when I
>>>> implemented the rest of the IPA revamp.
>>>>
>>>> Rested.  OK?
>>>>
>>>> On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>>>>
>>>>> This converts the lattice to store ranges in Value_Range instead of
>>>>> value_range (*) to make it type agnostic, and adjust all users
>>>>> accordingly.
>>>>>
>>>>> I think it is a good example on converting from static ranges to more
>>>>> general, type agnostic ones.
>>>>>
>>>>> I've been careful to make sure Value_Range never ends up on GC, since
>>>>> it contains an int_range_max and can expand on-demand onto the heap.
>>>>> Longer term storage for ranges should be done with vrange_storage, as
>>>>> per the previous patch ("Provide an API for ipa_vr").
>>>>>
>>>>> (*) I do know the Value_Range naming versus value_range is quite
>>>>> annoying, but it was a judgement call last release for the eventual
>>>>> migration to having "value_range" be a type agnostic range object.  We
>>>>> will ultimately rename Value_Range to value_range.
> 
> [...]
> 
>>>>> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
>>>>> index d4b9d4ac27e..bd5b1da17b2 100644
>>>>> --- a/gcc/ipa-cp.cc
>>>>> +++ b/gcc/ipa-cp.cc
>>>>> @@ -343,20 +343,29 @@ private:
>>>>>    class ipcp_vr_lattice
>>>>>    {
>>>>>    public:
>>>>> -  value_range m_vr;
>>>>> +  Value_Range m_vr;
>>>>>
>>>>>      inline bool bottom_p () const;
>>>>>      inline bool top_p () const;
>>>>> -  inline bool set_to_bottom ();
>>>>> -  bool meet_with (const value_range *p_vr);
>>>>> +  inline bool set_to_bottom (tree type);
>>>
>>> Requiring a type when setting a lattice to bottom makes for a weird
>>> interface, can't we set the underlying Value_Range to whatever... >
>>>>> +  bool meet_with (const vrange &p_vr);
>>>>>      bool meet_with (const ipcp_vr_lattice &other);
>>>>> -  void init () { gcc_assert (m_vr.undefined_p ()); }
>>>>> +  void init (tree type);
>>>>>      void print (FILE * f);
>>>>>
>>>>>    private:
>>>>> -  bool meet_with_1 (const value_range *other_vr);
>>>>> +  bool meet_with_1 (const vrange &other_vr);
>>>>>    };
>>>>>
>>>>> +inline void
>>>>> +ipcp_vr_lattice::init (tree type)
>>>>> +{
>>>>> +  if (type)
>>>>> +    m_vr.set_type (type);
>>>>> +
>>>>> +  // Otherwise m_vr will default to unsupported_range.
>>>
>>> ...this does?
>>>
>>> All users of the lattice check it for not being bottom first, so it
>>> should be safe.
>>>
>>> If it is not possible for some reason, then I guess we should add a bool
>>> flag to ipcp_vr_lattice instead, rather than looking up types of
>>> unusable lattices.  ipcp_vr_lattices don't live for long.
>>
>> The type was my least favorite part of this work.  And yes, your
>> suggestion would work.  I have tweaked the patch to force a VARYING for
>> an unsupported range which seems to do the trick.  It looks much
>> cleaner.  Thanks.
> 
> This version is much better indeed.
> 
> [...]
> 
>>>>> @@ -1912,29 +1917,33 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
>>>>>        return false;
>>>>>
>>>>>      range_op_handler handler (operation, dst_type);
>>>>> -  return (handler
>>>>> -         && handler.fold_range (*dst_vr, dst_type,
>>>>> -                                *src_vr, value_range (dst_type))
>>>>> -         && !dst_vr->varying_p ()
>>>>> -         && !dst_vr->undefined_p ());
>>>>> +  if (!handler)
>>>>> +    return false;
>>>>> +
>>>>> +  Value_Range varying (dst_type);
>>>>> +  varying.set_varying (dst_type);
>>>>> +
>>>>> +  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
>>>>> +         && !dst_vr.varying_p ()
>>>>> +         && !dst_vr.undefined_p ());
>>>>>    }
>>>>>
>>>>>    /* Determine value_range of JFUNC given that INFO describes the caller node or
>>>>>       the one it is inlined to, CS is the call graph edge corresponding to JFUNC
>>>>>       and PARM_TYPE of the parameter.  */
>>>>>
>>>>> -value_range
>>>>> -ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>>>> +void
>>>>> +ipa_value_range_from_jfunc (vrange &vr,
>>>>> +                           ipa_node_params *info, cgraph_edge *cs,
>>>>>                               ipa_jump_func *jfunc, tree parm_type)
>>>
>>> I assume that you decided to return the value in a parameter passed by
>>> reference instead of in return value for a good reason but then can we
>>> at least...
>>
>> vrange is an abstract type, plus it can be any size (int_range<3> has 3
>> sub-ranges, legacy value_range has 2 sub-ranges, frange is a totally
>> different object, etc).  Throughout all of ranger, returning a range is
>> done by passing by reference.  This has the added benefit that sometimes
>> we can set a return range by twiddling a few bits (foo.set_undefined())
>> instead of having to copy a full range back and forth.
>>
> 
> I see, thanks.
> 
> [...]
> 
>>
>> How's this?
> 
> One minor observation below...
> 
>>
>> Aldy
>>  From 2fd0ae47aa094675a02763e72d7bb7404ed9334b Mon Sep 17 00:00:00 2001
>> From: Aldy Hernandez <aldyh@redhat.com>
>> Date: Wed, 17 May 2023 11:29:34 +0200
>> Subject: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.
>>
>> This converts the lattice to store ranges in Value_Range instead of
>> value_range (*) to make it type agnostic, and adjust all users
>> accordingly.
>>
>> I've been careful to make sure Value_Range never ends up on GC, since
>> it contains an int_range_max and can expand on-demand onto the heap.
>> Longer term storage for ranges should be done with vrange_storage, as
>> per the previous patch ("Provide an API for ipa_vr").
>>
>> gcc/ChangeLog:
>>
>> 	* ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
>> 	(ipcp_vr_lattice::print): Call dump method.
>> 	(ipcp_vr_lattice::meet_with): Adjust for m_vr being a
>>          Value_Range.
>> 	(ipcp_vr_lattice::meet_with_1): Make argument a reference.
>> 	(ipcp_vr_lattice::set_to_bottom): Set varying for an unsupported
>> 	range.
>> 	(initialize_node_lattices): Pass type when appropriate.
>> 	(ipa_vr_operation_and_type_effects): Make type agnostic.
>> 	(ipa_value_range_from_jfunc): Same.
>> 	(propagate_vr_across_jump_function): Same.
>> 	* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
>> 	(evaluate_properties_for_edge): Same.
>> 	* ipa-prop.cc (ipa_vr::get_vrange): Same.
>> 	(ipcp_update_vr): Same.
>> 	* ipa-prop.h (ipa_value_range_from_jfunc): Same.
>> 	(ipa_range_set_and_normalize): Same.
>> ---
>>   gcc/ipa-cp.cc        | 148 ++++++++++++++++++++++++-------------------
>>   gcc/ipa-fnsummary.cc |  15 ++---
>>   gcc/ipa-prop.cc      |   5 +-
>>   gcc/ipa-prop.h       |  21 +++---
>>   4 files changed, 101 insertions(+), 88 deletions(-)
>>
>> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
>> index 0f37bb5e336..d77b9eab249 100644
>> --- a/gcc/ipa-cp.cc
>> +++ b/gcc/ipa-cp.cc
>> @@ -343,20 +343,29 @@ private:
>>   class ipcp_vr_lattice
>>   {
>>   public:
>> -  value_range m_vr;
>> +  Value_Range m_vr;
>>   
>>     inline bool bottom_p () const;
>>     inline bool top_p () const;
>>     inline bool set_to_bottom ();
>> -  bool meet_with (const value_range *p_vr);
>> +  bool meet_with (const vrange &p_vr);
>>     bool meet_with (const ipcp_vr_lattice &other);
>> -  void init () { gcc_assert (m_vr.undefined_p ()); }
>> +  void init (tree type);
>>     void print (FILE * f);
>>   
>>   private:
>> -  bool meet_with_1 (const value_range *other_vr);
>> +  bool meet_with_1 (const vrange &other_vr);
>>   };
>>   
>> +inline void
>> +ipcp_vr_lattice::init (tree type)
>> +{
>> +  if (type)
>> +    m_vr.set_type (type);
>> +
>> +  // Otherwise m_vr will default to unsupported_range.
>> +}
>> +
>>   /* Structure containing lattices for a parameter itself and for pieces of
>>      aggregates that are passed in the parameter or by a reference in a parameter
>>      plus some other useful flags.  */
>> @@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
>>   void
>>   ipcp_vr_lattice::print (FILE * f)
>>   {
>> -  dump_value_range (f, &m_vr);
>> +  m_vr.dump (f);
>>   }
>>   
>>   /* Print all ipcp_lattices of all functions to F.  */
>> @@ -1016,39 +1025,39 @@ set_agg_lats_contain_variable (class ipcp_param_lattices *plats)
>>   bool
>>   ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
>>   {
>> -  return meet_with_1 (&other.m_vr);
>> +  return meet_with_1 (other.m_vr);
>>   }
>>   
>> -/* Meet the current value of the lattice with value range described by VR
>> -   lattice.  */
>> +/* Meet the current value of the lattice with the range described by
>> +   P_VR.  */
>>   
>>   bool
>> -ipcp_vr_lattice::meet_with (const value_range *p_vr)
>> +ipcp_vr_lattice::meet_with (const vrange &p_vr)
>>   {
>>     return meet_with_1 (p_vr);
>>   }
>>   
>> -/* Meet the current value of the lattice with value range described by
>> -   OTHER_VR lattice.  Return TRUE if anything changed.  */
>> +/* Meet the current value of the lattice with the range described by
>> +   OTHER_VR.  Return TRUE if anything changed.  */
>>   
>>   bool
>> -ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
>> +ipcp_vr_lattice::meet_with_1 (const vrange &other_vr)
>>   {
>>     if (bottom_p ())
>>       return false;
>>   
>> -  if (other_vr->varying_p ())
>> +  if (other_vr.varying_p ())
>>       return set_to_bottom ();
>>   
>>     bool res;
>>     if (flag_checking)
>>       {
>> -      value_range save (m_vr);
>> -      res = m_vr.union_ (*other_vr);
>> +      Value_Range save (m_vr);
>> +      res = m_vr.union_ (other_vr);
>>         gcc_assert (res == (m_vr != save));
>>       }
>>     else
>> -    res = m_vr.union_ (*other_vr);
>> +    res = m_vr.union_ (other_vr);
>>     return res;
>>   }
>>   
>> @@ -1077,12 +1086,15 @@ ipcp_vr_lattice::set_to_bottom ()
>>   {
>>     if (m_vr.varying_p ())
>>       return false;
>> -  /* ?? We create all sorts of VARYING ranges for floats, structures,
>> -     and other types which we cannot handle as ranges.  We should
>> -     probably avoid handling them throughout the pass, but it's easier
>> -     to create a sensible VARYING here and let the lattice
>> -     propagate.  */
>> -  m_vr.set_varying (integer_type_node);
>> +
>> +  /* Setting an unsupported type here forces the temporary to default
>> +     to unsupported_range, which can handle VARYING/DEFINED ranges,
>> +     but nothing else (union, intersect, etc).  This allows us to set
>> +     bottoms on any ranges, and is safe as all users of the lattice
>> +     check for bottom first.  */
>> +  m_vr.set_type (void_type_node);
>> +  m_vr.set_varying (void_type_node);
>> +
>>     return true;
>>   }
>>   
>> @@ -1653,6 +1665,7 @@ initialize_node_lattices (struct cgraph_node *node)
>>     for (i = 0; i < ipa_get_param_count (info); i++)
>>       {
>>         ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
>> +      tree type = ipa_get_type (info, i);
>>         if (disable
>>   	  || !ipa_get_type (info, i)
>>   	  || (pre_modified && (surviving_params.length () <= (unsigned) i
>> @@ -1662,12 +1675,12 @@ initialize_node_lattices (struct cgraph_node *node)
>>   	  plats->ctxlat.set_to_bottom ();
>>   	  set_agg_lats_to_bottom (plats);
>>   	  plats->bits_lattice.set_to_bottom ();
>> -	  plats->m_value_range.m_vr = value_range ();
>> +	  plats->m_value_range.init (type);
>>   	  plats->m_value_range.set_to_bottom ();
> 
> This sequence of init(type) followed by set_to_bottom looks a little
> superfluous, is it?

init() will *unconditionally* set the range to undefined, and then 
set_to_bottom will *conditionally* set the range to varying if it's not 
already varying.  This was existing behavior.

If we remove the init(), the set_to_bottom may bail on entry if the 
range was already varying (of another type):


bool
ipcp_vr_lattice::set_to_bottom ()
{
   if (m_vr.varying_p ())
     return false;
...
...

I suppose if you're checking for varying/bottom before using the 
lattice, a varying of an unsupported range is the same as a varying of 
another type, and thus excluded from calculations (??).

I left the init there to avoid reading from m_vr with it uninitialized, 
or something, but I have no idea.

> 
>>   	}
>>         else
>>   	{
>> -	  plats->m_value_range.init ();
>> +	  plats->m_value_range.init (type);
> 
> Same here.

This one is different, because the entire context is:

	{
	  plats->m_value_range.init (type);
	  if (variable)
	    set_all_contains_variable (plats);
	}

So the init() sets undefined, whereas the conditional 
set_all_contains_variable() will call set_to_bottom which will set 
varying.  So that seems to change existing behavior.

I'm gonna retest (after Andrew's changes in this area), and commit as 
is, because it seems like the safe thing to do.  If you still think we 
should delete the first init() followed by set_to_bottom(), I'm more 
than happy to do it as a follow-up.

Aldy

> 
> But the patch is OK either way.
> 
> Thanks again,
> 
> Martin
> 
> 
>>   	  if (variable)
>>   	    set_all_contains_variable (plats);
>>   	}
>> @@ -1900,11 +1913,11 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
>>   
>>   /* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
>>      DST_TYPE on value range in SRC_VR and store it to DST_VR.  Return true if
>> -   the result is a range or an anti-range.  */
>> +   the result is a range that is not VARYING nor UNDEFINED.  */
>>   
>>   static bool
>> -ipa_vr_operation_and_type_effects (value_range *dst_vr,
>> -				   value_range *src_vr,
>> +ipa_vr_operation_and_type_effects (vrange &dst_vr,
>> +				   const vrange &src_vr,
>>   				   enum tree_code operation,
>>   				   tree dst_type, tree src_type)
>>   {
>> @@ -1912,29 +1925,35 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
>>       return false;
>>   
>>     range_op_handler handler (operation, dst_type);
>> -  return (handler
>> -	  && handler.fold_range (*dst_vr, dst_type,
>> -				 *src_vr, value_range (dst_type))
>> -	  && !dst_vr->varying_p ()
>> -	  && !dst_vr->undefined_p ());
>> +  if (!handler)
>> +    return false;
>> +
>> +  Value_Range varying (dst_type);
>> +  varying.set_varying (dst_type);
>> +
>> +  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
>> +	  && !dst_vr.varying_p ()
>> +	  && !dst_vr.undefined_p ());
>>   }
>>   
>>   /* Determine range of JFUNC given that INFO describes the caller node or
>>      the one it is inlined to, CS is the call graph edge corresponding to JFUNC
>>      and PARM_TYPE of the parameter.  */
>>   
>> -value_range
>> -ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>> +void
>> +ipa_value_range_from_jfunc (vrange &vr,
>> +			    ipa_node_params *info, cgraph_edge *cs,
>>   			    ipa_jump_func *jfunc, tree parm_type)
>>   {
>> -  value_range vr;
>> +  vr.set_undefined ();
>> +
>>     if (jfunc->m_vr)
>> -    ipa_vr_operation_and_type_effects (&vr,
>> -				       jfunc->m_vr,
>> +    ipa_vr_operation_and_type_effects (vr,
>> +				       *jfunc->m_vr,
>>   				       NOP_EXPR, parm_type,
>>   				       jfunc->m_vr->type ());
>>     if (vr.singleton_p ())
>> -    return vr;
>> +    return;
>>     if (jfunc->type == IPA_JF_PASS_THROUGH)
>>       {
>>         int idx;
>> @@ -1943,33 +1962,34 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>   					   ? cs->caller->inlined_to
>>   					   : cs->caller);
>>         if (!sum || !sum->m_vr)
>> -	return vr;
>> +	return;
>>   
>>         idx = ipa_get_jf_pass_through_formal_id (jfunc);
>>   
>>         if (!(*sum->m_vr)[idx].known_p ())
>> -	return vr;
>> +	return;
>>         tree vr_type = ipa_get_type (info, idx);
>> -      value_range srcvr;
>> +      Value_Range srcvr;
>>         (*sum->m_vr)[idx].get_vrange (srcvr);
>>   
>>         enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
>>   
>>         if (TREE_CODE_CLASS (operation) == tcc_unary)
>>   	{
>> -	  value_range res;
>> +	  Value_Range res (vr_type);
>>   
>> -	  if (ipa_vr_operation_and_type_effects (&res,
>> -						 &srcvr,
>> +	  if (ipa_vr_operation_and_type_effects (res,
>> +						 srcvr,
>>   						 operation, parm_type,
>>   						 vr_type))
>>   	    vr.intersect (res);
>>   	}
>>         else
>>   	{
>> -	  value_range op_res, res;
>> +	  Value_Range op_res (vr_type);
>> +	  Value_Range res (vr_type);
>>   	  tree op = ipa_get_jf_pass_through_operand (jfunc);
>> -	  value_range op_vr;
>> +	  Value_Range op_vr (vr_type);
>>   	  range_op_handler handler (operation, vr_type);
>>   
>>   	  ipa_range_set_and_normalize (op_vr, op);
>> @@ -1979,14 +1999,13 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
>>   	      || !handler.fold_range (op_res, vr_type, srcvr, op_vr))
>>   	    op_res.set_varying (vr_type);
>>   
>> -	  if (ipa_vr_operation_and_type_effects (&res,
>> -						 &op_res,
>> +	  if (ipa_vr_operation_and_type_effects (res,
>> +						 op_res,
>>   						 NOP_EXPR, parm_type,
>>   						 vr_type))
>>   	    vr.intersect (res);
>>   	}
>>       }
>> -  return vr;
>>   }
>>   
>>   /* Determine whether ITEM, jump function for an aggregate part, evaluates to a
>> @@ -2753,10 +2772,10 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>         if (src_lats->m_value_range.bottom_p ())
>>   	return dest_lat->set_to_bottom ();
>>   
>> -      value_range vr;
>> +      Value_Range vr (operand_type);
>>         if (TREE_CODE_CLASS (operation) == tcc_unary)
>> -	ipa_vr_operation_and_type_effects (&vr,
>> -					   &src_lats->m_value_range.m_vr,
>> +	ipa_vr_operation_and_type_effects (vr,
>> +					   src_lats->m_value_range.m_vr,
>>   					   operation, param_type,
>>   					   operand_type);
>>         /* A crude way to prevent unbounded number of value range updates
>> @@ -2765,8 +2784,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>         else if (!ipa_edge_within_scc (cs))
>>   	{
>>   	  tree op = ipa_get_jf_pass_through_operand (jfunc);
>> -	  value_range op_vr;
>> -	  value_range op_res,res;
>> +	  Value_Range op_vr (TREE_TYPE (op));
>> +	  Value_Range op_res (operand_type);
>>   	  range_op_handler handler (operation, operand_type);
>>   
>>   	  ipa_range_set_and_normalize (op_vr, op);
>> @@ -2777,8 +2796,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>   				      src_lats->m_value_range.m_vr, op_vr))
>>   	    op_res.set_varying (operand_type);
>>   
>> -	  ipa_vr_operation_and_type_effects (&vr,
>> -					     &op_res,
>> +	  ipa_vr_operation_and_type_effects (vr,
>> +					     op_res,
>>   					     NOP_EXPR, param_type,
>>   					     operand_type);
>>   	}
>> @@ -2786,14 +2805,14 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>   	{
>>   	  if (jfunc->m_vr)
>>   	    {
>> -	      value_range jvr;
>> -	      if (ipa_vr_operation_and_type_effects (&jvr, jfunc->m_vr,
>> +	      Value_Range jvr (param_type);
>> +	      if (ipa_vr_operation_and_type_effects (jvr, *jfunc->m_vr,
>>   						     NOP_EXPR,
>>   						     param_type,
>>   						     jfunc->m_vr->type ()))
>>   		vr.intersect (jvr);
>>   	    }
>> -	  return dest_lat->meet_with (&vr);
>> +	  return dest_lat->meet_with (vr);
>>   	}
>>       }
>>     else if (jfunc->type == IPA_JF_CONST)
>> @@ -2805,18 +2824,17 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
>>   	  if (TREE_OVERFLOW_P (val))
>>   	    val = drop_tree_overflow (val);
>>   
>> -	  value_range tmpvr (TREE_TYPE (val),
>> -			     wi::to_wide (val), wi::to_wide (val));
>> -	  return dest_lat->meet_with (&tmpvr);
>> +	  Value_Range tmpvr (val, val);
>> +	  return dest_lat->meet_with (tmpvr);
>>   	}
>>       }
>>   
>> -  value_range vr;
>> +  Value_Range vr (param_type);
>>     if (jfunc->m_vr
>> -      && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
>> +      && ipa_vr_operation_and_type_effects (vr, *jfunc->m_vr, NOP_EXPR,
>>   					    param_type,
>>   					    jfunc->m_vr->type ()))
>> -    return dest_lat->meet_with (&vr);
>> +    return dest_lat->meet_with (vr);
>>     else
>>       return dest_lat->set_to_bottom ();
>>   }
>> diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
>> index b328bb8ce14..cf416202920 100644
>> --- a/gcc/ipa-fnsummary.cc
>> +++ b/gcc/ipa-fnsummary.cc
>> @@ -475,7 +475,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
>>   	  && !c->agg_contents
>>   	  && (!val || TREE_CODE (val) != INTEGER_CST))
>>   	{
>> -	  value_range vr = avals->m_known_value_ranges[c->operand_num];
>> +	  Value_Range vr (avals->m_known_value_ranges[c->operand_num]);
>>   	  if (!vr.undefined_p ()
>>   	      && !vr.varying_p ()
>>   	      && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
>> @@ -630,8 +630,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>   		|| ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>>   	      {
>>   		/* Determine if we know constant value of the parameter.  */
>> -		tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
>> -						 ipa_get_type (callee_pi, i));
>> +		tree type = ipa_get_type (callee_pi, i);
>> +		tree cst = ipa_value_from_jfunc (caller_parms_info, jf, type);
>>   
>>   		if (!cst && e->call_stmt
>>   		    && i < (int)gimple_call_num_args (e->call_stmt))
>> @@ -659,10 +659,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>   		    && vrp_will_run_p (caller)
>>   		    && ipa_is_param_used_by_ipa_predicates (callee_pi, i))
>>   		  {
>> -		    value_range vr
>> -		       = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
>> -						     ipa_get_type (callee_pi,
>> -								   i));
>> +		    Value_Range vr (type);
>> +
>> +		    ipa_value_range_from_jfunc (vr, caller_parms_info, e, jf, type);
>>   		    if (!vr.undefined_p () && !vr.varying_p ())
>>   		      {
>>   			if (!avals->m_known_value_ranges.length ())
>> @@ -670,7 +669,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
>>   			    avals->m_known_value_ranges.safe_grow (count, true);
>>   			    for (int i = 0; i < count; ++i)
>>   			      new (&avals->m_known_value_ranges[i])
>> -				value_range ();
>> +				Value_Range ();
>>   			  }
>>   			avals->m_known_value_ranges[i] = vr;
>>   		      }
>> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
>> index ab6de9f10da..bbfe0f8aa45 100644
>> --- a/gcc/ipa-prop.cc
>> +++ b/gcc/ipa-prop.cc
>> @@ -198,8 +198,9 @@ ipa_vr::equal_p (const vrange &r) const
>>   }
>>   
>>   void
>> -ipa_vr::get_vrange (vrange &r) const
>> +ipa_vr::get_vrange (Value_Range &r) const
>>   {
>> +  r.set_type (m_type);
>>     m_storage->get_vrange (r, m_type);
>>   }
>>   
>> @@ -5963,7 +5964,7 @@ ipcp_update_vr (struct cgraph_node *node)
>>   
>>         if (vr[i].known_p ())
>>   	{
>> -	  value_range tmp;
>> +	  Value_Range tmp;
>>   	  vr[i].get_vrange (tmp);
>>   
>>   	  if (!tmp.undefined_p () && !tmp.varying_p ())
>> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
>> index f306f8a377e..3a591a8f44d 100644
>> --- a/gcc/ipa-prop.h
>> +++ b/gcc/ipa-prop.h
>> @@ -314,7 +314,7 @@ public:
>>     void set_unknown ();
>>     bool known_p () const { return m_storage != NULL; }
>>     tree type () const { return m_type; }
>> -  void get_vrange (vrange &) const;
>> +  void get_vrange (Value_Range &) const;
>>     bool equal_p (const vrange &) const;
>>     const vrange_storage *storage () const { return m_storage; }
>>     void streamer_read (lto_input_block *, data_in *);
>> @@ -530,7 +530,7 @@ public:
>>     auto_vec<ipa_argagg_value, 32> m_known_aggs;
>>   
>>     /* Vector describing known value ranges of arguments.  */
>> -  auto_vec<value_range, 32> m_known_value_ranges;
>> +  auto_vec<Value_Range, 32> m_known_value_ranges;
>>   };
>>   
>>   inline
>> @@ -582,7 +582,7 @@ public:
>>     vec<ipa_argagg_value> m_known_aggs = vNULL;
>>   
>>     /* Vector describing known value ranges of arguments.  */
>> -  vec<value_range> m_known_value_ranges = vNULL;
>> +  vec<Value_Range> m_known_value_ranges = vNULL;
>>   };
>>   
>>   inline
>> @@ -1194,8 +1194,8 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
>>   						     cgraph_edge *,
>>   						     int,
>>   						     ipa_jump_func *);
>> -value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
>> -					ipa_jump_func *, tree);
>> +void ipa_value_range_from_jfunc (vrange &, ipa_node_params *, cgraph_edge *,
>> +				 ipa_jump_func *, tree);
>>   void ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node,
>>   				     ipa_agg_jump_function *agg_jfunc,
>>   				     unsigned dst_index,
>> @@ -1218,17 +1218,12 @@ void ipa_cp_cc_finalize (void);
>>      non-zero.  */
>>   
>>   inline void
>> -ipa_range_set_and_normalize (irange &r, tree val)
>> +ipa_range_set_and_normalize (vrange &r, tree val)
>>   {
>> -  if (TREE_CODE (val) == INTEGER_CST)
>> -    {
>> -      wide_int w = wi::to_wide (val);
>> -      r.set (TREE_TYPE (val), w, w);
>> -    }
>> -  else if (TREE_CODE (val) == ADDR_EXPR)
>> +  if (TREE_CODE (val) == ADDR_EXPR)
>>       r.set_nonzero (TREE_TYPE (val));
>>     else
>> -    r.set_varying (TREE_TYPE (val));
>> +    r.set (val, val);
>>   }
>>   
>>   #endif /* IPA_PROP_H */
>> -- 
>> 2.40.1
>
diff mbox series

Patch

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index d4b9d4ac27e..bd5b1da17b2 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -343,20 +343,29 @@  private:
 class ipcp_vr_lattice
 {
 public:
-  value_range m_vr;
+  Value_Range m_vr;
 
   inline bool bottom_p () const;
   inline bool top_p () const;
-  inline bool set_to_bottom ();
-  bool meet_with (const value_range *p_vr);
+  inline bool set_to_bottom (tree type);
+  bool meet_with (const vrange &p_vr);
   bool meet_with (const ipcp_vr_lattice &other);
-  void init () { gcc_assert (m_vr.undefined_p ()); }
+  void init (tree type);
   void print (FILE * f);
 
 private:
-  bool meet_with_1 (const value_range *other_vr);
+  bool meet_with_1 (const vrange &other_vr);
 };
 
+inline void
+ipcp_vr_lattice::init (tree type)
+{
+  if (type)
+    m_vr.set_type (type);
+
+  // Otherwise m_vr will default to unsupported_range.
+}
+
 /* Structure containing lattices for a parameter itself and for pieces of
    aggregates that are passed in the parameter or by a reference in a parameter
    plus some other useful flags.  */
@@ -585,7 +594,7 @@  ipcp_bits_lattice::print (FILE *f)
 void
 ipcp_vr_lattice::print (FILE * f)
 {
-  dump_value_range (f, &m_vr);
+  m_vr.dump (f);
 }
 
 /* Print all ipcp_lattices of all functions to F.  */
@@ -1016,14 +1025,14 @@  set_agg_lats_contain_variable (class ipcp_param_lattices *plats)
 bool
 ipcp_vr_lattice::meet_with (const ipcp_vr_lattice &other)
 {
-  return meet_with_1 (&other.m_vr);
+  return meet_with_1 (other.m_vr);
 }
 
 /* Meet the current value of the lattice with value range described by VR
    lattice.  */
 
 bool
-ipcp_vr_lattice::meet_with (const value_range *p_vr)
+ipcp_vr_lattice::meet_with (const vrange &p_vr)
 {
   return meet_with_1 (p_vr);
 }
@@ -1032,23 +1041,23 @@  ipcp_vr_lattice::meet_with (const value_range *p_vr)
    OTHER_VR lattice.  Return TRUE if anything changed.  */
 
 bool
-ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
+ipcp_vr_lattice::meet_with_1 (const vrange &other_vr)
 {
   if (bottom_p ())
     return false;
 
-  if (other_vr->varying_p ())
-    return set_to_bottom ();
+  if (other_vr.varying_p ())
+    return set_to_bottom (other_vr.type ());
 
   bool res;
   if (flag_checking)
     {
-      value_range save (m_vr);
-      res = m_vr.union_ (*other_vr);
+      Value_Range save (m_vr);
+      res = m_vr.union_ (other_vr);
       gcc_assert (res == (m_vr != save));
     }
   else
-    res = m_vr.union_ (*other_vr);
+    res = m_vr.union_ (other_vr);
   return res;
 }
 
@@ -1073,16 +1082,11 @@  ipcp_vr_lattice::bottom_p () const
    previously was in a different state.  */
 
 bool
-ipcp_vr_lattice::set_to_bottom ()
+ipcp_vr_lattice::set_to_bottom (tree type)
 {
   if (m_vr.varying_p ())
     return false;
-  /* ?? We create all sorts of VARYING ranges for floats, structures,
-     and other types which we cannot handle as ranges.  We should
-     probably avoid handling them throughout the pass, but it's easier
-     to create a sensible VARYING here and let the lattice
-     propagate.  */
-  m_vr.set_varying (integer_type_node);
+  m_vr.set_varying (type);
   return true;
 }
 
@@ -1518,14 +1522,14 @@  intersect_argaggs_with (vec<ipa_argagg_value> &elts,
    return true is any of them has not been marked as such so far.  */
 
 static inline bool
-set_all_contains_variable (class ipcp_param_lattices *plats)
+set_all_contains_variable (class ipcp_param_lattices *plats, tree type)
 {
   bool ret;
   ret = plats->itself.set_contains_variable ();
   ret |= plats->ctxlat.set_contains_variable ();
   ret |= set_agg_lats_contain_variable (plats);
   ret |= plats->bits_lattice.set_to_bottom ();
-  ret |= plats->m_value_range.set_to_bottom ();
+  ret |= plats->m_value_range.set_to_bottom (type);
   return ret;
 }
 
@@ -1653,6 +1657,7 @@  initialize_node_lattices (struct cgraph_node *node)
   for (i = 0; i < ipa_get_param_count (info); i++)
     {
       ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+      tree type = ipa_get_type (info, i);
       if (disable
 	  || !ipa_get_type (info, i)
 	  || (pre_modified && (surviving_params.length () <= (unsigned) i
@@ -1662,14 +1667,14 @@  initialize_node_lattices (struct cgraph_node *node)
 	  plats->ctxlat.set_to_bottom ();
 	  set_agg_lats_to_bottom (plats);
 	  plats->bits_lattice.set_to_bottom ();
-	  plats->m_value_range.m_vr = value_range ();
-	  plats->m_value_range.set_to_bottom ();
+	  plats->m_value_range.init (type);
+	  plats->m_value_range.set_to_bottom (type);
 	}
       else
 	{
-	  plats->m_value_range.init ();
+	  plats->m_value_range.init (type);
 	  if (variable)
-	    set_all_contains_variable (plats);
+	    set_all_contains_variable (plats, type);
 	}
     }
 
@@ -1903,8 +1908,8 @@  ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
    the result is a range or an anti-range.  */
 
 static bool
-ipa_vr_operation_and_type_effects (value_range *dst_vr,
-				   value_range *src_vr,
+ipa_vr_operation_and_type_effects (vrange &dst_vr,
+				   const vrange &src_vr,
 				   enum tree_code operation,
 				   tree dst_type, tree src_type)
 {
@@ -1912,29 +1917,33 @@  ipa_vr_operation_and_type_effects (value_range *dst_vr,
     return false;
 
   range_op_handler handler (operation, dst_type);
-  return (handler
-	  && handler.fold_range (*dst_vr, dst_type,
-				 *src_vr, value_range (dst_type))
-	  && !dst_vr->varying_p ()
-	  && !dst_vr->undefined_p ());
+  if (!handler)
+    return false;
+
+  Value_Range varying (dst_type);
+  varying.set_varying (dst_type);
+
+  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
+	  && !dst_vr.varying_p ()
+	  && !dst_vr.undefined_p ());
 }
 
 /* Determine value_range of JFUNC given that INFO describes the caller node or
    the one it is inlined to, CS is the call graph edge corresponding to JFUNC
    and PARM_TYPE of the parameter.  */
 
-value_range
-ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
+void
+ipa_value_range_from_jfunc (vrange &vr,
+			    ipa_node_params *info, cgraph_edge *cs,
 			    ipa_jump_func *jfunc, tree parm_type)
 {
-  value_range vr;
   if (jfunc->m_vr)
-    ipa_vr_operation_and_type_effects (&vr,
-				       jfunc->m_vr,
+    ipa_vr_operation_and_type_effects (vr,
+				       *jfunc->m_vr,
 				       NOP_EXPR, parm_type,
 				       jfunc->m_vr->type ());
   if (vr.singleton_p ())
-    return vr;
+    return;
   if (jfunc->type == IPA_JF_PASS_THROUGH)
     {
       int idx;
@@ -1943,33 +1952,34 @@  ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
 					   ? cs->caller->inlined_to
 					   : cs->caller);
       if (!sum || !sum->m_vr)
-	return vr;
+	return;
 
       idx = ipa_get_jf_pass_through_formal_id (jfunc);
 
       if (!(*sum->m_vr)[idx].known_p ())
-	return vr;
+	return;
       tree vr_type = ipa_get_type (info, idx);
-      value_range srcvr;
+      Value_Range srcvr (vr_type);
       (*sum->m_vr)[idx].get_vrange (srcvr, vr_type);
 
       enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
 
       if (TREE_CODE_CLASS (operation) == tcc_unary)
 	{
-	  value_range res;
+	  Value_Range res (vr_type);
 
-	  if (ipa_vr_operation_and_type_effects (&res,
-						 &srcvr,
+	  if (ipa_vr_operation_and_type_effects (res,
+						 srcvr,
 						 operation, parm_type,
 						 vr_type))
 	    vr.intersect (res);
 	}
       else
 	{
-	  value_range op_res, res;
+	  Value_Range op_res (vr_type);
+	  Value_Range res (vr_type);
 	  tree op = ipa_get_jf_pass_through_operand (jfunc);
-	  value_range op_vr;
+	  Value_Range op_vr (vr_type);
 	  range_op_handler handler (operation, vr_type);
 
 	  ipa_range_set_and_normalize (op_vr, op);
@@ -1979,14 +1989,13 @@  ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
 	      || !handler.fold_range (op_res, vr_type, srcvr, op_vr))
 	    op_res.set_varying (vr_type);
 
-	  if (ipa_vr_operation_and_type_effects (&res,
-						 &op_res,
+	  if (ipa_vr_operation_and_type_effects (res,
+						 op_res,
 						 NOP_EXPR, parm_type,
 						 vr_type))
 	    vr.intersect (res);
 	}
     }
-  return vr;
 }
 
 /* Determine whether ITEM, jump function for an aggregate part, evaluates to a
@@ -2739,7 +2748,7 @@  propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
   if (!param_type
       || (!INTEGRAL_TYPE_P (param_type)
 	  && !POINTER_TYPE_P (param_type)))
-    return dest_lat->set_to_bottom ();
+    return dest_lat->set_to_bottom (param_type);
 
   if (jfunc->type == IPA_JF_PASS_THROUGH)
     {
@@ -2751,12 +2760,12 @@  propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
       tree operand_type = ipa_get_type (caller_info, src_idx);
 
       if (src_lats->m_value_range.bottom_p ())
-	return dest_lat->set_to_bottom ();
+	return dest_lat->set_to_bottom (operand_type);
 
-      value_range vr;
+      Value_Range vr (operand_type);
       if (TREE_CODE_CLASS (operation) == tcc_unary)
-	ipa_vr_operation_and_type_effects (&vr,
-					   &src_lats->m_value_range.m_vr,
+	ipa_vr_operation_and_type_effects (vr,
+					   src_lats->m_value_range.m_vr,
 					   operation, param_type,
 					   operand_type);
       /* A crude way to prevent unbounded number of value range updates
@@ -2765,8 +2774,8 @@  propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
       else if (!ipa_edge_within_scc (cs))
 	{
 	  tree op = ipa_get_jf_pass_through_operand (jfunc);
-	  value_range op_vr;
-	  value_range op_res,res;
+	  Value_Range op_vr (TREE_TYPE (op));
+	  Value_Range op_res (operand_type);
 	  range_op_handler handler (operation, operand_type);
 
 	  ipa_range_set_and_normalize (op_vr, op);
@@ -2777,8 +2786,8 @@  propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
 				      src_lats->m_value_range.m_vr, op_vr))
 	    op_res.set_varying (operand_type);
 
-	  ipa_vr_operation_and_type_effects (&vr,
-					     &op_res,
+	  ipa_vr_operation_and_type_effects (vr,
+					     op_res,
 					     NOP_EXPR, param_type,
 					     operand_type);
 	}
@@ -2786,14 +2795,14 @@  propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
 	{
 	  if (jfunc->m_vr)
 	    {
-	      value_range jvr;
-	      if (ipa_vr_operation_and_type_effects (&jvr, jfunc->m_vr,
+	      Value_Range jvr (param_type);
+	      if (ipa_vr_operation_and_type_effects (jvr, *jfunc->m_vr,
 						     NOP_EXPR,
 						     param_type,
 						     jfunc->m_vr->type ()))
 		vr.intersect (jvr);
 	    }
-	  return dest_lat->meet_with (&vr);
+	  return dest_lat->meet_with (vr);
 	}
     }
   else if (jfunc->type == IPA_JF_CONST)
@@ -2805,20 +2814,19 @@  propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
 	  if (TREE_OVERFLOW_P (val))
 	    val = drop_tree_overflow (val);
 
-	  value_range tmpvr (TREE_TYPE (val),
-			     wi::to_wide (val), wi::to_wide (val));
-	  return dest_lat->meet_with (&tmpvr);
+	  Value_Range tmpvr (val, val);
+	  return dest_lat->meet_with (tmpvr);
 	}
     }
 
   value_range vr;
   if (jfunc->m_vr
-      && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
+      && ipa_vr_operation_and_type_effects (vr, *jfunc->m_vr, NOP_EXPR,
 					    param_type,
 					    jfunc->m_vr->type ()))
-    return dest_lat->meet_with (&vr);
+    return dest_lat->meet_with (vr);
   else
-    return dest_lat->set_to_bottom ();
+    return dest_lat->set_to_bottom (param_type);
 }
 
 /* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
@@ -3209,7 +3217,8 @@  propagate_constants_across_call (struct cgraph_edge *cs)
     {
       for (i = 0; i < parms_count; i++)
 	ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
-								 i));
+								 i),
+					  ipa_get_type (callee_info, i));
       return ret;
     }
   args_count = ipa_get_cs_argument_count (args);
@@ -3220,7 +3229,8 @@  propagate_constants_across_call (struct cgraph_edge *cs)
   if (call_passes_through_thunk (cs))
     {
       ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
-							       0));
+							       0),
+					ipa_get_type (callee_info, 0));
       i = 1;
     }
   else
@@ -3234,7 +3244,7 @@  propagate_constants_across_call (struct cgraph_edge *cs)
 
       dest_plats = ipa_get_parm_lattices (callee_info, i);
       if (availability == AVAIL_INTERPOSABLE)
-	ret |= set_all_contains_variable (dest_plats);
+	ret |= set_all_contains_variable (dest_plats, param_type);
       else
 	{
 	  ret |= propagate_scalar_across_jump_function (cs, jump_func,
@@ -3251,11 +3261,12 @@  propagate_constants_across_call (struct cgraph_edge *cs)
 	    ret |= propagate_vr_across_jump_function (cs, jump_func,
 						      dest_plats, param_type);
 	  else
-	    ret |= dest_plats->m_value_range.set_to_bottom ();
+	    ret |= dest_plats->m_value_range.set_to_bottom (param_type);
 	}
     }
   for (; i < parms_count; i++)
-    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i));
+    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i),
+				      ipa_get_type (callee_info, i));
 
   return ret;
 }
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index b328bb8ce14..0474af8991e 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -475,7 +475,7 @@  evaluate_conditions_for_known_args (struct cgraph_node *node,
 	  && !c->agg_contents
 	  && (!val || TREE_CODE (val) != INTEGER_CST))
 	{
-	  value_range vr = avals->m_known_value_ranges[c->operand_num];
+	  Value_Range vr (avals->m_known_value_ranges[c->operand_num]);
 	  if (!vr.undefined_p ()
 	      && !vr.varying_p ()
 	      && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
@@ -630,8 +630,8 @@  evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 		|| ipa_is_param_used_by_ipa_predicates (callee_pi, i))
 	      {
 		/* Determine if we know constant value of the parameter.  */
-		tree cst = ipa_value_from_jfunc (caller_parms_info, jf,
-						 ipa_get_type (callee_pi, i));
+		tree type = ipa_get_type (callee_pi, i);
+		tree cst = ipa_value_from_jfunc (caller_parms_info, jf, type);
 
 		if (!cst && e->call_stmt
 		    && i < (int)gimple_call_num_args (e->call_stmt))
@@ -659,10 +659,10 @@  evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 		    && vrp_will_run_p (caller)
 		    && ipa_is_param_used_by_ipa_predicates (callee_pi, i))
 		  {
-		    value_range vr
-		       = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
-						     ipa_get_type (callee_pi,
-								   i));
+		    Value_Range vr (type);
+
+		    ipa_value_range_from_jfunc (vr, caller_parms_info, e, jf,
+						ipa_get_type (callee_pi, i));
 		    if (!vr.undefined_p () && !vr.varying_p ())
 		      {
 			if (!avals->m_known_value_ranges.length ())
@@ -670,7 +670,7 @@  evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 			    avals->m_known_value_ranges.safe_grow (count, true);
 			    for (int i = 0; i < count; ++i)
 			      new (&avals->m_known_value_ranges[i])
-				value_range ();
+				Value_Range ();
 			  }
 			avals->m_known_value_ranges[i] = vr;
 		      }
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 4ace410de49..1a71d7969ea 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -5939,7 +5939,7 @@  ipcp_update_vr (struct cgraph_node *node)
       if (vr[i].known_p ())
 	{
 	  tree type = TREE_TYPE (ddef);
-	  value_range tmp;
+	  Value_Range tmp (type);
 	  vr[i].get_vrange (tmp, type);
 
 	  if (!tmp.undefined_p () && !tmp.varying_p ())
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 3b580ebb903..3921e33940d 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -530,7 +530,7 @@  public:
   auto_vec<ipa_argagg_value, 32> m_known_aggs;
 
   /* Vector describing known value ranges of arguments.  */
-  auto_vec<value_range, 32> m_known_value_ranges;
+  auto_vec<Value_Range, 32> m_known_value_ranges;
 };
 
 inline
@@ -582,7 +582,7 @@  public:
   vec<ipa_argagg_value> m_known_aggs = vNULL;
 
   /* Vector describing known value ranges of arguments.  */
-  vec<value_range> m_known_value_ranges = vNULL;
+  vec<Value_Range> m_known_value_ranges = vNULL;
 };
 
 inline
@@ -1194,8 +1194,8 @@  ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
 						     cgraph_edge *,
 						     int,
 						     ipa_jump_func *);
-value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
-					ipa_jump_func *, tree);
+void ipa_value_range_from_jfunc (vrange &, ipa_node_params *, cgraph_edge *,
+				 ipa_jump_func *, tree);
 void ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node,
 				     ipa_agg_jump_function *agg_jfunc,
 				     unsigned dst_index,
@@ -1218,17 +1218,12 @@  void ipa_cp_cc_finalize (void);
    non-zero.  */
 
 inline void
-ipa_range_set_and_normalize (irange &r, tree val)
+ipa_range_set_and_normalize (vrange &r, tree val)
 {
-  if (TREE_CODE (val) == INTEGER_CST)
-    {
-      wide_int w = wi::to_wide (val);
-      r.set (TREE_TYPE (val), w, w);
-    }
-  else if (TREE_CODE (val) == ADDR_EXPR)
+  if (TREE_CODE (val) == ADDR_EXPR)
     r.set_nonzero (TREE_TYPE (val));
   else
-    r.set_varying (TREE_TYPE (val));
+    r.set (val, val);
 }
 
 #endif /* IPA_PROP_H */