new API for value_range

Message ID a7ea8660-ec2c-6f1b-63aa-ac5865e65470@redhat.com
State New
Headers show
Series
  • new API for value_range
Related show

Commit Message

Aldy Hernandez Oct. 9, 2018, 4:22 p.m.
I'm assuming the silence on the RFC means nobody is viscerally opposed 
to it, so here goes the actual implementation ;-).

	FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html

My aim is no change to the current functionality, but there are some 
things that changed slightly (with no appreciable change in 
bootstrapability or tests).

1.  Primarily, we were building value_ranges by modifying them in-flight 
with no regards to the validity of the resulting range.  By enforcing 
the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but 
left the equivalence bits uncleared.  This comment in the original 
header file indicates that this is invalid behavior:

   /* Set of SSA names whose value ranges are equivalent to this one.
      This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */

The API now enforces this upon construction.

2. I also saw us setting min/max when VARYING or UNDEFINED was set. 
This is invalid.  Although these values were being ignored, the API now 
enforces this.

3. I saw one case in set_value_range_with_overflow() were we were 
building an invalid range with swapped ranges, where we were silently 
depending on somebody further up the call chain to swap them for us. 
I've fixed this at creation.

4. There is one assert in ipcp_vr_lattice which I hope to remove, but 
left as proof that the original VR_UNDEFINED set was not necessary, as 
it is now done by default on an empty constructor:

-  void init () { m_vr.type = VR_UNDEFINED; }
+  void init () { gcc_assert (m_vr.undefined_p ()); }

One last note.  The file tree-vrp.c already has a cripple API of sorts 
in the form of functions (set_value_range_to_varying, etc).  I have 
tried to keep those functions available, by calling the API under the 
covers, but would be okay in removing them altogether as a follow-up.

Please refer to the RFC wrt the min/max/vrtype accessors, as well as the 
new tree type field.

I am quoting the class declaration below to make it easy to review at a 
high level.

Tested on x86-64 Linux.  All languages, including Ada and Go.

OK for trunk?

Aldy

class GTY((for_user)) value_range
{
  public:
   value_range ();
   value_range (tree type);
   value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
   bool operator== (const value_range &) const;
   bool operator!= (const value_range &) const;
   void intersect (const value_range *);
   void union_ (const value_range *);
   /* Like operator== but ignore equivalence bitmap.  */
   bool ignore_equivs_equal_p (const value_range &) const;
   /* Like a operator= but update equivalence bitmap efficiently.  */
   void copy_with_equiv_update (const value_range *);

   /* Types of value ranges.  */
   bool undefined_p () const;
   bool varying_p () const;
   bool symbolic_p () const;
   bool numeric_p () const;
   void set_undefined (tree = NULL);
   void set_varying (tree = NULL);

   /* Equivalence bitmap methods.  */
   bitmap equiv () const;
   void set_equiv (bitmap);
   void equiv_free ();
   void equiv_copy (const value_range *);
   void equiv_clear ();
   void equiv_and (const value_range *);
   void equiv_ior (const value_range *);

   /* Misc methods.  */
   tree type () const;
   bool null_p () const;
   bool may_contain_p (tree) const;
   tree singleton () const;
   void set_and_canonicalize (enum value_range_type, tree, tree, tree, 
bitmap);
   void dump () const;

   /* Temporary accessors that should eventually be removed.  */
   enum value_range_type vrtype () const;
   tree min () const;
   tree max () const;

  private:
   void set (value_range_type, tree type, tree, tree, bitmap);
   void check ();
   bool equal_p (const value_range &, bool ignore_equivs) const;

   enum value_range_type m_vrtype;
  public:
   /* These should be private, but GTY is a piece of crap.  */
   tree m_min;
   tree m_max;
   tree m_type;
   /* Set of SSA names whose value ranges are equivalent to this one.
      This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
   bitmap m_equiv;
};

Comments

Richard Biener Oct. 10, 2018, 10:27 a.m. | #1
On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> I'm assuming the silence on the RFC means nobody is viscerally opposed
> to it, so here goes the actual implementation ;-).
>
>         FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
>
> My aim is no change to the current functionality, but there are some
> things that changed slightly (with no appreciable change in
> bootstrapability or tests).
>
> 1.  Primarily, we were building value_ranges by modifying them in-flight
> with no regards to the validity of the resulting range.  By enforcing
> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
> left the equivalence bits uncleared.  This comment in the original
> header file indicates that this is invalid behavior:
>
>    /* Set of SSA names whose value ranges are equivalent to this one.
>       This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
>
> The API now enforces this upon construction.
>
> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
> This is invalid.  Although these values were being ignored, the API now
> enforces this.
>
> 3. I saw one case in set_value_range_with_overflow() were we were
> building an invalid range with swapped ranges, where we were silently
> depending on somebody further up the call chain to swap them for us.
> I've fixed this at creation.
>
> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
> left as proof that the original VR_UNDEFINED set was not necessary, as
> it is now done by default on an empty constructor:
>
> -  void init () { m_vr.type = VR_UNDEFINED; }
> +  void init () { gcc_assert (m_vr.undefined_p ()); }
>
> One last note.  The file tree-vrp.c already has a cripple API of sorts
> in the form of functions (set_value_range_to_varying, etc).  I have
> tried to keep those functions available, by calling the API under the
> covers, but would be okay in removing them altogether as a follow-up.
>
> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
> new tree type field.
>
> I am quoting the class declaration below to make it easy to review at a
> high level.
>
> Tested on x86-64 Linux.  All languages, including Ada and Go.
>
> OK for trunk?

Reviewing in patch order.

> Aldy
>
> class GTY((for_user)) value_range
> {
>   public:
>    value_range ();
>    value_range (tree type);
>    value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
>    bool operator== (const value_range &) const;
>    bool operator!= (const value_range &) const;
>    void intersect (const value_range *);
>    void union_ (const value_range *);

with trailing underscore?  seriously?

>    /* Like operator== but ignore equivalence bitmap.  */
>    bool ignore_equivs_equal_p (const value_range &) const;
>    /* Like a operator= but update equivalence bitmap efficiently.  */
>    void copy_with_equiv_update (const value_range *);
>
>    /* Types of value ranges.  */
>    bool undefined_p () const;
>    bool varying_p () const;
>    bool symbolic_p () const;
>    bool numeric_p () const;
>    void set_undefined (tree = NULL);
>    void set_varying (tree = NULL);

I'd appreciate comments on those predicates, esp. as you
replace positive tests by negative ones like in

   /* If we found any usable VR, set the VR to ssa_name and create a
      PUSH old value in the stack with the old VR.  */
-  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+  if (!vr.undefined_p () && !vr.varying_p ())
     {

I'd also spell numeric_p as constant_p or drop it alltogether
since !symbolic_p should imply it given varying_p and undefined_p
are just some special-cases of "numeric_p" (full and empty range).

That said, for the time being I'd use non_symbolic_range_or_anti_range_p
instead of numeric_p () (seeing that you maybe want to hide the fact
that we have anti-ranges?)

-  value_range vr = VR_INITIALIZER;
+  value_range vr (TREE_TYPE (name));

so you basically forgo with the fact that empty ranges are universal?
I don't like it too much that we have to invent a type here.  Why enforce this
and not allow/force type == NULL_TREE for empty ranges?

One could argue VARYING is also universal to some extent and useful
only with context, so similar argument applies to your change forcing
a type for set_value_range_to_varying.

-      value_range vr = VR_INITIALIZER;
+      value_range vr;

oh, so you do have a default constructor.

>
>    /* Equivalence bitmap methods.  */
>    bitmap equiv () const;
>    void set_equiv (bitmap);

Err, I think we've settled on _not_ wrapping all member accesses
with get/set methods, didn't we?  I personally dislike that very much.

>    void equiv_free ();
>    void equiv_copy (const value_range *);
>    void equiv_clear ();
>    void equiv_and (const value_range *);
>    void equiv_ior (const value_range *);

Likewise I find this useless abstraction.  It's even questionable
if _free/_clear/_copy are good APIs here.  This should be all
hidden in intersect/union which I do not find in the API at all...

>
>    /* Misc methods.  */
>    tree type () const;

type() and vrtype() is confusing - value_type() and range_kind() maybe?

>    bool null_p () const;
>    bool may_contain_p (tree) const;
>    tree singleton () const;

No documentation? :/   Why null_p but singleton (instead of singleton_p)?

>    void set_and_canonicalize (enum value_range_type, tree, tree, tree,
> bitmap);

Why's that necessary if you enforce sanity?

>    void dump () const;
>
>    /* Temporary accessors that should eventually be removed.  */
>    enum value_range_type vrtype () const;
>    tree min () const;
>    tree max () const;
>
>   private:
>    void set (value_range_type, tree type, tree, tree, bitmap);
>    void check ();
>    bool equal_p (const value_range &, bool ignore_equivs) const;
>
>    enum value_range_type m_vrtype;
>   public:
>    /* These should be private, but GTY is a piece of crap.  */
>    tree m_min;
>    tree m_max;
>    tree m_type;

m_type is redundant (see above).

>    /* Set of SSA names whose value ranges are equivalent to this one.
>       This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
>    bitmap m_equiv;
> };



>
Aldy Hernandez Oct. 11, 2018, 8:19 a.m. | #2
Hi Richard.  Thanks for reviewing.

On 10/10/18 6:27 AM, Richard Biener wrote:
> On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>
>> I'm assuming the silence on the RFC means nobody is viscerally opposed
>> to it, so here goes the actual implementation ;-).
>>
>>          FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
>>
>> My aim is no change to the current functionality, but there are some
>> things that changed slightly (with no appreciable change in
>> bootstrapability or tests).
>>
>> 1.  Primarily, we were building value_ranges by modifying them in-flight
>> with no regards to the validity of the resulting range.  By enforcing
>> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
>> left the equivalence bits uncleared.  This comment in the original
>> header file indicates that this is invalid behavior:
>>
>>     /* Set of SSA names whose value ranges are equivalent to this one.
>>        This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
>>
>> The API now enforces this upon construction.
>>
>> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
>> This is invalid.  Although these values were being ignored, the API now
>> enforces this.
>>
>> 3. I saw one case in set_value_range_with_overflow() were we were
>> building an invalid range with swapped ranges, where we were silently
>> depending on somebody further up the call chain to swap them for us.
>> I've fixed this at creation.
>>
>> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
>> left as proof that the original VR_UNDEFINED set was not necessary, as
>> it is now done by default on an empty constructor:
>>
>> -  void init () { m_vr.type = VR_UNDEFINED; }
>> +  void init () { gcc_assert (m_vr.undefined_p ()); }
>>
>> One last note.  The file tree-vrp.c already has a cripple API of sorts
>> in the form of functions (set_value_range_to_varying, etc).  I have
>> tried to keep those functions available, by calling the API under the
>> covers, but would be okay in removing them altogether as a follow-up.
>>
>> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
>> new tree type field.
>>
>> I am quoting the class declaration below to make it easy to review at a
>> high level.
>>
>> Tested on x86-64 Linux.  All languages, including Ada and Go.
>>
>> OK for trunk?
> 
> Reviewing in patch order.
> 
>> Aldy
>>
>> class GTY((for_user)) value_range
>> {
>>    public:
>>     value_range ();
>>     value_range (tree type);
>>     value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
>>     bool operator== (const value_range &) const;
>>     bool operator!= (const value_range &) const;
>>     void intersect (const value_range *);
>>     void union_ (const value_range *);
> 
> with trailing underscore?  seriously?

Hey!  You complained about Union() last year, at which point the 
consensus was that trailing underscores would be ok for symbol names 
that clashed with keywords.

And yes, it was also discussed whether we should overload | and ^ for 
union and intersection, but was denied for readability and what have yous.

> 
>>     /* Like operator== but ignore equivalence bitmap.  */
>>     bool ignore_equivs_equal_p (const value_range &) const;
>>     /* Like a operator= but update equivalence bitmap efficiently.  */
>>     void copy_with_equiv_update (const value_range *);
>>
>>     /* Types of value ranges.  */
>>     bool undefined_p () const;
>>     bool varying_p () const;
>>     bool symbolic_p () const;
>>     bool numeric_p () const;
>>     void set_undefined (tree = NULL);
>>     void set_varying (tree = NULL);
> 
> I'd appreciate comments on those predicates, esp. as you
> replace positive tests by negative ones like in

Done.

> 
>     /* If we found any usable VR, set the VR to ssa_name and create a
>        PUSH old value in the stack with the old VR.  */
> -  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> +  if (!vr.undefined_p () && !vr.varying_p ())
>       {
> 
> I'd also spell numeric_p as constant_p or drop it alltogether
> since !symbolic_p should imply it given varying_p and undefined_p
> are just some special-cases of "numeric_p" (full and empty range).

Done.

> 
> That said, for the time being I'd use non_symbolic_range_or_anti_range_p
> instead of numeric_p () (seeing that you maybe want to hide the fact
> that we have anti-ranges?)

Errr... No.

> 
> -  value_range vr = VR_INITIALIZER;
> +  value_range vr (TREE_TYPE (name));
> 
> so you basically forgo with the fact that empty ranges are universal?
> I don't like it too much that we have to invent a type here.  Why enforce this
> and not allow/force type == NULL_TREE for empty ranges?
> 
> One could argue VARYING is also universal to some extent and useful
> only with context, so similar argument applies to your change forcing
> a type for set_value_range_to_varying.
> 
> -      value_range vr = VR_INITIALIZER;
> +      value_range vr;
> 
> oh, so you do have a default constructor.
> 
>>
>>     /* Equivalence bitmap methods.  */
>>     bitmap equiv () const;
>>     void set_equiv (bitmap);
> 
> Err, I think we've settled on _not_ wrapping all member accesses
> with get/set methods, didn't we?  I personally dislike that very much.
> 
>>     void equiv_free ();
>>     void equiv_copy (const value_range *);
>>     void equiv_clear ();
>>     void equiv_and (const value_range *);
>>     void equiv_ior (const value_range *);
> 
> Likewise I find this useless abstraction.  It's even questionable
> if _free/_clear/_copy are good APIs here.  This should be all
> hidden in intersect/union which I do not find in the API at all...

I missed that discussion.  We did?  I dislike exposing the internals. 
Abstracting things out makes it easier to change things in the future-- 
or insert instrumenting code, or whatever.

That said, I have removed copy/free/and/or.  As you said, it was much 
easier to make the details internal to the intersect/union member functions.

However, I have kept:

   bitmap equiv () const;
   void set_equiv (bitmap);
   void equiv_clear ();

I think we can get away with just having a clear, instead of a free, as 
it's all in an obstack and there doesn't seem to be any consistent use 
of free vs. clear throughout (except one or two, which I've kept).

Also, we don't really need to expose set_equiv(), but for its one use in 
vr_values::add_equivalence().  One option could be to make vr_values and 
value_ranges friends and let add_equivalence touch m_equiv.  But that's 
a bit heavy handed.

Or we could add this to the API instead of set_equiv():

void
value_range::add_equivalence (bitmap_obstack obstack, tree var)
{
}

I don't know how I feel about passing the obtack, or including 
"bitmap.h" from everywhere tree-vrp.h is used (that is, everywhere).

For equiv(), we could remove virtually all of its uses, since 99% of 
them are in the form:

	set_value_range (vr, VR_SOMETHING, min, max, vr->equiv ())

Instead we could We could provide:

	vr->update (VR_SOMETHING, min, max);

...which is just like set_value_range, but keeping the equivalences intact.

 > hidden in intersect/union which I do not find in the API at all...

How could you, it was front and center ;-):

   void intersect (const value_range *);
   void union_ (const value_range *);

> 
>>
>>     /* Misc methods.  */
>>     tree type () const;
> 
> type() and vrtype() is confusing - value_type() and range_kind() maybe?

How about we keep type(), since 99% of all uses of "type" in the 
compiler are "tree type", so it's easy to figure out.  And instead of 
range_kind() we use kind().  It's already obvious it's a range, so 
vr->kind() reads fine IMO.

> 
>>     bool null_p () const;
>>     bool may_contain_p (tree) const;
>>     tree singleton () const;
> 
> No documentation? :/   Why null_p but singleton (instead of singleton_p)?

Documented.

Singleton returns the singleton if found, otherwise returns NULL. 
NULL_P returns true/or false.  I thought the preferred way was for _p to 
always return booleans.

I don't feel strongly, so I've renamed it to singleton_p() since a 
NULL_TREE is as good as false.  Another option is:

	bool singleton_p (tree *result = NULL)

Hmmm...I like this last one.  What do you think?

> 
>>     void set_and_canonicalize (enum value_range_type, tree, tree, tree,
>> bitmap);
> 
> Why's that necessary if you enforce sanity?

Canonicalize also does some optimizations like converting anti-ranges 
into ranges if possible.  Although I would be OK with putting that 
functionality in value_range::set() to be done on creation, I don't know 
how I feel about polluting the creation code with fixing swapped min/max:

   /* Wrong order for min and max, to swap them and the VR type we need
      to adjust them.  */

It feels wrong to construct a range with swapped end-points, and hope 
things turn out ok.  ISTM that canonicalize() clearly specifies intent: 
I'm giving you a shitty range, fix it.

Thoughts?

> 
>>     void dump () const;
>>
>>     /* Temporary accessors that should eventually be removed.  */
>>     enum value_range_type vrtype () const;
>>     tree min () const;
>>     tree max () const;
>>
>>    private:
>>     void set (value_range_type, tree type, tree, tree, bitmap);
>>     void check ();
>>     bool equal_p (const value_range &, bool ignore_equivs) const;
>>
>>     enum value_range_type m_vrtype;
>>    public:
>>     /* These should be private, but GTY is a piece of crap.  */
>>     tree m_min;
>>     tree m_max;
>>     tree m_type;
> 
> m_type is redundant (see above).

Removed.

Tested on x86-64 Linux.

Aldy

p.s. Oh yeah, it wouldn't be an Aldy patch without an irrelevant bit 
added for good measure:

+void
+bitmap_head::dump ()
+{
+  debug (this);
+}

I find having ->dump() available for each and every structure in GCC 
helpful in debugging.  At some point we should standardize on dump(FILE 
*) and debug() to dump to stderr.  But alas, there are too many dump()'s 
that already dump to stderr :-/.
gcc/

	* bitmap.c (bitmap_head::dump): New.
	* bitmap.h (bitmap_head): Add dump().
	* gimple-ssa-evrp-analyze.c
	(evrp_range_analyzer::try_find_new_range): Adjust for value_range API.
	(evrp_range_analyzer::set_ssa_range_info): Same.
	(evrp_range_analyzer::record_ranges_from_phis): Same.
	(evrp_range_analyzer::record_ranges_from_stmt): Same.
	* gimple-ssa-evrp.c (evrp_dom_walker::before_dom_children): Same.
	* gimple-ssa-sprintf.c (get_int_range): Same.
	(format_integer): Same.
	(sprintf_dom_walker::handle_gimple_call): Same.
	* ipa-cp.c (ipcp_vr_lattice::meet_with_1): Same.
	(ipcp_vr_lattice::top_p): Same.
	(ipcp_vr_lattice::bottom_p): Same.
	(ipcp_vr_lattice::set_to_bottom): Same.
	(ipa_vr_operation_and_type_effects): Same.
	(propagate_vr_across_jump_function): Same.
	(ipcp_store_vr_results): Same.
	* ipa-prop.c (struct ipa_vr_ggc_hash_traits): Same.
	(ipa_print_node_jump_functions_for_edge): Same.
	(ipa_get_value_range): Same.
	(ipa_compute_jump_functions_for_edge): Same.
	(ipa_write_jump_function): Same.
	* tree-ssa-dom.c (simplify_stmt_for_jump_threading): Same.
	* tree-ssa-threadedge.c (record_temporary_equivalences_from_phis):
	Same.
	* vr-values.c (set_value_range_to_nonnegative): Same.
	(set_value_range_to_truthvalue): Same.
	(vr_values::get_value_range): Same.
	(vr_values::set_defs_to_varying): Same.
	(vr_values::update_value_range): Same.
	(symbolic_range_based_on_p): Same.
	(vr_values::op_with_boolean_value_range_p): Same.
	(vr_values::extract_range_for_var_from_comparison_expr): Same.
	(vr_values::extract_range_from_ssa_name): Same.
	(vr_values::extract_range_from_binary_expr): Same.
	(vr_values::extract_range_from_unary_expr): Same.
	(vr_values::extract_range_from_cond_expr): Same.
	(vr_values::extract_range_from_comparison): Same.
	(vr_values::check_for_binary_op_overflow): Same.
	(vr_values::extract_range_basic): Same.
	(vr_values::extract_range_from_assignment): Same.
	(compare_ranges): Same.
	(compare_range_with_value): Same.
	(vr_values::adjust_range_with_scev): Same.
	(vrp_valueize): Same.
	(vrp_valueize_1): Same.
	(vr_values::get_vr_for_comparison): Same.
	(vr_values::compare_name_with_value): Same.
	(vr_values::compare_names): Same.
	(vr_values::vrp_evaluate_conditional): Same.
	(find_case_label_ranges): Same.
	(vr_values::vrp_visit_switch_stmt): Same.
	(vr_values::extract_range_from_phi_node): Same.
	(vr_values::simplify_div_or_mod_using_ranges): Same.
	(vr_values::simplify_bit_ops_using_ranges): Same.
	(test_for_singularity): Same.
	(range_fits_type_p): Same.
	(vr_values::simplify_cond_using_ranges_1): Same.
	(vr_values::simplify_switch_using_ranges): Same.
	(vr_values::simplify_float_conversion_using_ranges): Same.
	(vr_values::two_valued_val_range_p): Same.
	(vr_values::add_equivalence): Rewrite to return adjusted value
	instead of setting a pointer.
	* vr-values.h (vr_values::add_equivalence): Adjust to return
	value.
	(VR_INITIALIZER): Remove.
	* tree-vrp.c (value_range::set): New.
	(value_range::value_range): New.
	(value_range::deep_copy): New.
	(value_range::check): New.
	(value_range::equal_p): New.
	(value_range::ignore_equivs_equal_p): New.
	(value_range::operator==): New.
	(value_range::operator!=): New.
	(value_range::symbolic_p): New.
	(value_range::numeric_p): New.
	(value_range::set_undefined): New.
	(value_range::set_varying): New.
	(value_range::may_contain_p): New.
	(value_range::equiv_clear): New.
	(value_range::singleton_p): New.
	(value_range::intersect): New.
	(value_range::dump): New.
	(value_range::set_and_canonicalize): New.
	(set_value_range): Adjust for value_range API.
	(set_value_range_to_undefined): Same.
	(set_value_range_to_varying): Same.
	(set_and_canonicalize_value_range): Same.
	(set_value_range_to_nonnull): Same.
	(set_value_range_to_null): Same.
	(range_is_null): Same.
	(range_is_nonnull): Same.
	(range_int_cst_p): Same.
	(range_int_cst_singleton_p): Same.
	(symbolic_range_p): Same.
	(range_includes_zero_p): Same.
	(value_range_constant_singleton): Same.
	(vrp_set_zero_nonzero_bits): Same.
	(ranges_from_anti_range): Same.
	(extract_range_into_wide_ints): Same.
	(extract_range_from_multiplicative_op): Same.
	(set_value_range_with_overflow): Same.
	(extract_range_from_binary_expr_1): Same.
	(extract_range_from_unary_expr): Same.
	(dump_value_range): Same.
	(debug_value_range): Same.
	(vrp_prop::check_array_ref): Same.
	(vrp_prop::check_mem_ref): Same.
	(vrp_prop::vrp_initialize): Same.
	(vrp_prop::visit_stmt): Same.
	(intersect_ranges): Same.
	(vrp_prop::visit_phi): Same.
	(vrp_prop::vrp_finalize): Same.
	(determine_value_range_1): Same.
	(determine_value_range): Same.
	(vrp_intersect_ranges_1): Rename to...
	(vrp_intersect_1): this.
	(vrp_intersect_ranges): Rename to...
	(value_range::intersect_helper): ...this.
	(vrp_meet_1): Rename to...
	(value_range::union_helper): ...this.
	(vrp_meet): Rename to...
	(value_range::union_): ...this.
	(copy_value_range): Remove.
	* tree-vrp.h (struct value_range): Rewrite into a proper class.
	(value_range::vrtype): New.
	(value_range::type): New.
	(value_range::equiv): New.
	(value_range::min): New.
	(value_range::max): New.
	(value_range::varying_p): New.
	(value_range::undefined_p): New.
	(value_range::set_equiv): New.
	(value_range::null_p): New.
	(copy_value_range): Remove.

diff --git a/gcc/bitmap.c b/gcc/bitmap.c
index d7464d78f20..538c4143cbe 100644
--- a/gcc/bitmap.c
+++ b/gcc/bitmap.c
@@ -2164,6 +2164,12 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+void
+bitmap_head::dump ()
+{
+  debug (this);
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/bitmap.h b/gcc/bitmap.h
index bdf074729df..57ae4a61086 100644
--- a/gcc/bitmap.h
+++ b/gcc/bitmap.h
@@ -243,6 +243,7 @@ struct GTY(()) bitmap_head {
   bitmap_element * GTY((skip(""))) current; /* Last element looked at.  */
   bitmap_obstack *obstack;		/* Obstack to allocate elements from.
 					   If NULL, then use GGC allocation.  */
+  void dump ();
 };
 
 /* Global data */
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 25e01e4092b..f64b3d4065b 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -3139,7 +3139,7 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
     return NULL_RTX;
 
   wide_int min, max;
-  enum value_range_type rng = get_range_info (bound, &min, &max);
+  enum value_range_kind rng = get_range_info (bound, &min, &max);
   if (rng != VR_RANGE)
     return NULL_RTX;
 
@@ -3227,7 +3227,7 @@ determine_block_size (tree len, rtx len_rtx,
   else
     {
       wide_int min, max;
-      enum value_range_type range_type = VR_UNDEFINED;
+      enum value_range_kind range_type = VR_UNDEFINED;
 
       /* Determine bounds from the type.  */
       if (tree_fits_uhwi_p (TYPE_MIN_VALUE (TREE_TYPE (len))))
@@ -3629,7 +3629,7 @@ compute_objsize (tree dest, int ostype)
 	      && INTEGRAL_TYPE_P (TREE_TYPE (off)))
 	    {
 	      wide_int min, max;
-	      enum value_range_type rng = get_range_info (off, &min, &max);
+	      enum value_range_kind rng = get_range_info (off, &min, &max);
 
 	      if (rng == VR_RANGE)
 		{
diff --git a/gcc/calls.c b/gcc/calls.c
index 80af5c3b3b3..8978d3b42fd 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1255,7 +1255,7 @@ get_size_range (tree exp, tree range[2], bool allow_zero /* = false */)
   bool integral = INTEGRAL_TYPE_P (exptype);
 
   wide_int min, max;
-  enum value_range_type range_type;
+  enum value_range_kind range_type;
 
   if (integral)
     range_type = determine_value_range (exp, &min, &max);
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 59cedeafd71..4977eef9810 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -9255,7 +9255,7 @@ bool
 expr_not_equal_to (tree t, const wide_int &w)
 {
   wide_int min, max, nz;
-  value_range_type rtype;
+  value_range_kind rtype;
   switch (TREE_CODE (t))
     {
     case INTEGER_CST:
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fe6bc08bdd9..fd48bbf9af4 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -649,7 +649,7 @@ size_must_be_zero_p (tree size)
     return false;
 
   wide_int min, max;
-  enum value_range_type rtype = get_range_info (size, &min, &max);
+  enum value_range_kind rtype = get_range_info (size, &min, &max);
   if (rtype != VR_ANTI_RANGE)
     return false;
 
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 83e22735571..7dfec9120ab 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -2123,7 +2123,7 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
       && SSA_NAME_RANGE_INFO (node))
     {
       wide_int min, max, nonzero_bits;
-      value_range_type range_type = get_range_info (node, &min, &max);
+      value_range_kind range_type = get_range_info (node, &min, &max);
 
       if (range_type == VR_VARYING)
 	pp_printf (buffer, "# RANGE VR_VARYING");
diff --git a/gcc/gimple-ssa-evrp-analyze.c b/gcc/gimple-ssa-evrp-analyze.c
index e9afa80e191..83917f5eb0a 100644
--- a/gcc/gimple-ssa-evrp-analyze.c
+++ b/gcc/gimple-ssa-evrp-analyze.c
@@ -82,7 +82,7 @@ value_range *
 evrp_range_analyzer::try_find_new_range (tree name,
 				    tree op, tree_code code, tree limit)
 {
-  value_range vr = VR_INITIALIZER;
+  value_range vr;
   value_range *old_vr = get_value_range (name);
 
   /* Discover VR when condition is true.  */
@@ -90,11 +90,11 @@ evrp_range_analyzer::try_find_new_range (tree name,
 							 limit, &vr);
   /* If we found any usable VR, set the VR to ssa_name and create a
      PUSH old value in the stack with the old VR.  */
-  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+  if (!vr.undefined_p () && !vr.varying_p ())
     {
-      if (old_vr->type == vr.type
-	  && vrp_operand_equal_p (old_vr->min, vr.min)
-	  && vrp_operand_equal_p (old_vr->max, vr.max))
+      if (old_vr->kind () == vr.kind ()
+	  && vrp_operand_equal_p (old_vr->min (), vr.min ())
+	  && vrp_operand_equal_p (old_vr->max (), vr.max ()))
 	return NULL;
       value_range *new_vr = vr_values->allocate_value_range ();
       *new_vr = vr;
@@ -110,13 +110,10 @@ evrp_range_analyzer::set_ssa_range_info (tree lhs, value_range *vr)
   /* Set the SSA with the value range.  */
   if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
     {
-      if ((vr->type == VR_RANGE
-	   || vr->type == VR_ANTI_RANGE)
-	  && (TREE_CODE (vr->min) == INTEGER_CST)
-	  && (TREE_CODE (vr->max) == INTEGER_CST))
-	set_range_info (lhs, vr->type,
-			wi::to_wide (vr->min),
-			wi::to_wide (vr->max));
+      if (vr->constant_p ())
+	set_range_info (lhs, vr->kind (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
     }
   else if (POINTER_TYPE_P (TREE_TYPE (lhs))
 	   && range_includes_zero_p (vr) == 0)
@@ -241,7 +238,7 @@ evrp_range_analyzer::record_ranges_from_phis (basic_block bb)
       if (virtual_operand_p (lhs))
 	continue;
 
-      value_range vr_result = VR_INITIALIZER;
+      value_range vr_result;
       bool interesting = stmt_interesting_for_vrp (phi);
       if (!has_unvisited_preds && interesting)
 	vr_values->extract_range_from_phi_node (phi, &vr_result);
@@ -284,7 +281,7 @@ evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
   else if (stmt_interesting_for_vrp (stmt))
     {
       edge taken_edge;
-      value_range vr = VR_INITIALIZER;
+      value_range vr;
       vr_values->extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
       if (output)
 	{
@@ -315,7 +312,7 @@ evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
 		 bitmaps.  Ugh.  */
 	      value_range *new_vr = vr_values->allocate_value_range ();
 	      *new_vr = vr;
-	      new_vr->equiv = NULL;
+	      new_vr->equiv_clear ();
 	      push_value_range (output, new_vr);
 	    }
 	}
diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 50e8adc1aad..b075c1051d8 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -161,8 +161,7 @@ evrp_dom_walker::before_dom_children (basic_block bb)
 	      value_range *vr = evrp_range_analyzer.get_value_range (output);
 
 	      /* Mark stmts whose output we fully propagate for removal.  */
-	      if ((vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
-		  && (val = value_range_constant_singleton (vr))
+	      if ((val = value_range_constant_singleton (vr))
 		  && may_propagate_copy (output, val)
 		  && !stmt_could_throw_p (stmt)
 		  && !gimple_has_side_effects (stmt))
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index 471bfc45eb8..90f028d50bd 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -1052,9 +1052,7 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 	{
 	  /* Try to determine the range of values of the integer argument.  */
 	  value_range *vr = vr_values->get_value_range (arg);
-	  if (vr->type == VR_RANGE
-	      && TREE_CODE (vr->min) == INTEGER_CST
-	      && TREE_CODE (vr->max) == INTEGER_CST)
+	  if (range_int_cst_p (vr))
 	    {
 	      HOST_WIDE_INT type_min
 		= (TYPE_UNSIGNED (argtype)
@@ -1063,8 +1061,8 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 
 	      HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype));
 
-	      *pmin = TREE_INT_CST_LOW (vr->min);
-	      *pmax = TREE_INT_CST_LOW (vr->max);
+	      *pmin = TREE_INT_CST_LOW (vr->min ());
+	      *pmax = TREE_INT_CST_LOW (vr->max ());
 
 	      if (*pmin < *pmax)
 		{
@@ -1354,12 +1352,10 @@ format_integer (const directive &dir, tree arg, vr_values *vr_values)
       /* Try to determine the range of values of the integer argument
 	 (range information is not available for pointers).  */
       value_range *vr = vr_values->get_value_range (arg);
-      if (vr->type == VR_RANGE
-	  && TREE_CODE (vr->min) == INTEGER_CST
-	  && TREE_CODE (vr->max) == INTEGER_CST)
+      if (range_int_cst_p (vr))
 	{
-	  argmin = vr->min;
-	  argmax = vr->max;
+	  argmin = vr->min ();
+	  argmax = vr->max ();
 
 	  /* Set KNOWNRANGE if the argument is in a known subrange
 	     of the directive's type and neither width nor precision
@@ -1372,12 +1368,11 @@ format_integer (const directive &dir, tree arg, vr_values *vr_values)
 	  res.argmin = argmin;
 	  res.argmax = argmax;
 	}
-      else if (vr->type == VR_ANTI_RANGE)
+      else if (vr->kind () == VR_ANTI_RANGE)
 	{
 	  /* Handle anti-ranges if/when bug 71690 is resolved.  */
 	}
-      else if (vr->type == VR_VARYING
-	       || vr->type == VR_UNDEFINED)
+      else if (vr->varying_p () || vr->undefined_p ())
 	{
 	  /* The argument here may be the result of promoting the actual
 	     argument to int.  Try to determine the type of the actual
@@ -3903,12 +3898,10 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi)
 	     and use the greater of the two at level 1 and the smaller
 	     of them at level 2.  */
 	  value_range *vr = evrp_range_analyzer.get_value_range (size);
-	  if (vr->type == VR_RANGE
-	      && TREE_CODE (vr->min) == INTEGER_CST
-	      && TREE_CODE (vr->max) == INTEGER_CST)
+	  if (range_int_cst_p (vr))
 	    dstsize = (warn_level < 2
-		       ? TREE_INT_CST_LOW (vr->max)
-		       : TREE_INT_CST_LOW (vr->min));
+		       ? TREE_INT_CST_LOW (vr->max ())
+		       : TREE_INT_CST_LOW (vr->min ()));
 
 	  /* The destination size is not constant.  If the function is
 	     bounded (e.g., snprintf) a lower bound of zero doesn't
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
index d1b1de4a2d5..9d2d68ad54b 100644
--- a/gcc/gimple-ssa-warn-alloca.c
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -272,7 +272,7 @@ alloca_call_type_by_arg (tree arg, tree arg_casted, edge e,
       && TREE_CODE (limit) == SSA_NAME)
     {
       wide_int min, max;
-      value_range_type range_type = get_range_info (limit, &min, &max);
+      value_range_kind range_type = get_range_info (limit, &min, &max);
 
       if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
 	return alloca_type_and_limit (ALLOCA_BOUND_UNKNOWN);
@@ -364,7 +364,7 @@ alloca_call_type (gimple *stmt, bool is_vla, tree *invalid_casted_type)
   // Check the range info if available.
   if (TREE_CODE (len) == SSA_NAME)
     {
-      value_range_type range_type = get_range_info (len, &min, &max);
+      value_range_kind range_type = get_range_info (len, &min, &max);
       if (range_type == VR_RANGE)
 	{
 	  if (wi::leu_p (max, max_size))
diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index ea30b7108f8..e3cbf42f2d9 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -312,7 +312,7 @@ builtin_memref::extend_offset_range (tree offset)
   if (TREE_CODE (offset) == SSA_NAME)
     {
       wide_int min, max;
-      value_range_type rng = get_range_info (offset, &min, &max);
+      value_range_kind rng = get_range_info (offset, &min, &max);
       if (rng == VR_RANGE)
 	{
 	  offrange[0] += offset_int::from (min, SIGNED);
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 27ae8e0fe27..4471bae11c7 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -314,7 +314,7 @@ public:
   inline bool set_to_bottom ();
   bool meet_with (const value_range *p_vr);
   bool meet_with (const ipcp_vr_lattice &other);
-  void init () { m_vr.type = VR_UNDEFINED; }
+  void init () { gcc_assert (m_vr.undefined_p ()); }
   void print (FILE * f);
 
 private:
@@ -914,28 +914,21 @@ ipcp_vr_lattice::meet_with (const value_range *p_vr)
   return meet_with_1 (p_vr);
 }
 
-/* Meet the current value of the lattice with value ranfge described by
-   OTHER_VR lattice.  */
+/* Meet the current value of the lattice with value range described by
+   OTHER_VR lattice.  Return TRUE if anything changed.  */
 
 bool
 ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
 {
-  tree min = m_vr.min, max = m_vr.max;
-  value_range_type type = m_vr.type;
-
   if (bottom_p ())
     return false;
 
-  if (other_vr->type == VR_VARYING)
+  if (other_vr->varying_p ())
     return set_to_bottom ();
 
-  vrp_meet (&m_vr, other_vr);
-  if (type != m_vr.type
-      || min != m_vr.min
-      || max != m_vr.max)
-    return true;
-  else
-    return false;
+  value_range save (m_vr);
+  m_vr.union_ (other_vr);
+  return !m_vr.ignore_equivs_equal_p (save);
 }
 
 /* Return true if value range information in the lattice is yet unknown.  */
@@ -943,7 +936,7 @@ ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
 bool
 ipcp_vr_lattice::top_p () const
 {
-  return m_vr.type == VR_UNDEFINED;
+  return m_vr.undefined_p ();
 }
 
 /* Return true if value range information in the lattice is known to be
@@ -952,7 +945,7 @@ ipcp_vr_lattice::top_p () const
 bool
 ipcp_vr_lattice::bottom_p () const
 {
-  return m_vr.type == VR_VARYING;
+  return m_vr.varying_p ();
 }
 
 /* Set value range information in the lattice to bottom.  Return true if it
@@ -961,9 +954,9 @@ ipcp_vr_lattice::bottom_p () const
 bool
 ipcp_vr_lattice::set_to_bottom ()
 {
-  if (m_vr.type == VR_VARYING)
+  if (m_vr.varying_p ())
     return false;
-  m_vr.type = VR_VARYING;
+  m_vr.set_varying ();
   return true;
 }
 
@@ -1882,12 +1875,11 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr, value_range *src_vr,
 				   enum tree_code operation,
 				   tree dst_type, tree src_type)
 {
-  memset (dst_vr, 0, sizeof (*dst_vr));
+  *dst_vr = value_range ();
   extract_range_from_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
-  if (dst_vr->type == VR_RANGE || dst_vr->type == VR_ANTI_RANGE)
-    return true;
-  else
+  if (dst_vr->varying_p () || dst_vr->undefined_p ())
     return false;
+  return true;
 }
 
 /* Propagate value range across jump function JFUNC that is associated with
@@ -1940,11 +1932,7 @@ 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;
-	  memset (&tmpvr, 0, sizeof (tmpvr));
-	  tmpvr.type = VR_RANGE;
-	  tmpvr.min = val;
-	  tmpvr.max = val;
+	  value_range tmpvr (VR_RANGE, val, val);
 	  return dest_lat->meet_with (&tmpvr);
 	}
     }
@@ -1953,7 +1941,7 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
   if (jfunc->m_vr
       && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
 					    param_type,
-					    TREE_TYPE (jfunc->m_vr->min)))
+					    jfunc->m_vr->type ()))
     return dest_lat->meet_with (&vr);
   else
     return dest_lat->set_to_bottom ();
@@ -5028,9 +5016,9 @@ ipcp_store_vr_results (void)
 	      && !plats->m_value_range.top_p ())
 	    {
 	      vr.known = true;
-	      vr.type = plats->m_value_range.m_vr.type;
-	      vr.min = wi::to_wide (plats->m_value_range.m_vr.min);
-	      vr.max = wi::to_wide (plats->m_value_range.m_vr.max);
+	      vr.type = plats->m_value_range.m_vr.kind ();
+	      vr.min = wi::to_wide (plats->m_value_range.m_vr.min ());
+	      vr.max = wi::to_wide (plats->m_value_range.m_vr.max ());
 	    }
 	  else
 	    {
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 8b19fe3f391..1e40997c92c 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -113,16 +113,16 @@ struct ipa_vr_ggc_hash_traits : public ggc_cache_remove <value_range *>
   static hashval_t
   hash (const value_range *p)
     {
-      gcc_checking_assert (!p->equiv);
-      inchash::hash hstate (p->type);
-      hstate.add_ptr (p->min);
-      hstate.add_ptr (p->max);
+      gcc_checking_assert (!p->equiv ());
+      inchash::hash hstate (p->kind ());
+      hstate.add_ptr (p->min ());
+      hstate.add_ptr (p->max ());
       return hstate.end ();
     }
   static bool
   equal (const value_range *a, const value_range *b)
     {
-      return a->type == b->type && a->min == b->min && a->max == b->max;
+      return a->ignore_equivs_equal_p (*b);
     }
   static void
   mark_empty (value_range *&p)
@@ -398,10 +398,10 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
 	{
 	  fprintf (f, "         VR  ");
 	  fprintf (f, "%s[",
-		   (jump_func->m_vr->type == VR_ANTI_RANGE) ? "~" : "");
-	  print_decs (wi::to_wide (jump_func->m_vr->min), f);
+		   (jump_func->m_vr->kind () == VR_ANTI_RANGE) ? "~" : "");
+	  print_decs (wi::to_wide (jump_func->m_vr->min ()), f);
 	  fprintf (f, ", ");
-	  print_decs (wi::to_wide (jump_func->m_vr->max), f);
+	  print_decs (wi::to_wide (jump_func->m_vr->max ()), f);
 	  fprintf (f, "]\n");
 	}
       else
@@ -1789,13 +1789,9 @@ ipa_get_value_range (value_range *tmp)
    value_ranges.  */
 
 static value_range *
-ipa_get_value_range (enum value_range_type type, tree min, tree max)
+ipa_get_value_range (enum value_range_kind type, tree min, tree max)
 {
-  value_range tmp;
-  tmp.type = type;
-  tmp.min = min;
-  tmp.max = max;
-  tmp.equiv = NULL;
+  value_range tmp (type, min, max);
   return ipa_get_value_range (&tmp);
 }
 
@@ -1804,7 +1800,7 @@ ipa_get_value_range (enum value_range_type type, tree min, tree max)
    same value_range structures.  */
 
 static void
-ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_type type,
+ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_kind type,
 		  tree min, tree max)
 {
   jf->m_vr = ipa_get_value_range (type, min, max);
@@ -1884,22 +1880,19 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
       else
 	{
 	  wide_int min, max;
-	  value_range_type type;
+	  value_range_kind type;
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
 	      && (type = get_range_info (arg, &min, &max))
 	      && (type == VR_RANGE || type == VR_ANTI_RANGE))
 	    {
-	      value_range tmpvr,resvr;
-
-	      tmpvr.type = type;
-	      tmpvr.min = wide_int_to_tree (TREE_TYPE (arg), min);
-	      tmpvr.max = wide_int_to_tree (TREE_TYPE (arg), max);
-	      tmpvr.equiv = NULL;
-	      memset (&resvr, 0, sizeof (resvr));
+	      value_range resvr;
+	      value_range tmpvr (type,
+				 wide_int_to_tree (TREE_TYPE (arg), min),
+				 wide_int_to_tree (TREE_TYPE (arg), max));
 	      extract_range_from_unary_expr (&resvr, NOP_EXPR, param_type,
 					     &tmpvr, TREE_TYPE (arg));
-	      if (resvr.type == VR_RANGE || resvr.type == VR_ANTI_RANGE)
+	      if (!resvr.undefined_p () && !resvr.varying_p ())
 		ipa_set_jfunc_vr (jfunc, &resvr);
 	      else
 		gcc_assert (!jfunc->m_vr);
@@ -4126,9 +4119,9 @@ ipa_write_jump_function (struct output_block *ob,
   if (jump_func->m_vr)
     {
       streamer_write_enum (ob->main_stream, value_rang_type,
-			   VR_LAST, jump_func->m_vr->type);
-      stream_write_tree (ob, jump_func->m_vr->min, true);
-      stream_write_tree (ob, jump_func->m_vr->max, true);
+			   VR_LAST, jump_func->m_vr->kind ());
+      stream_write_tree (ob, jump_func->m_vr->min (), true);
+      stream_write_tree (ob, jump_func->m_vr->max (), true);
     }
 }
 
@@ -4216,7 +4209,7 @@ ipa_read_jump_function (struct lto_input_block *ib,
   bool vr_known = bp_unpack_value (&vr_bp, 1);
   if (vr_known)
     {
-      enum value_range_type type = streamer_read_enum (ib, value_range_type,
+      enum value_range_kind type = streamer_read_enum (ib, value_range_kind,
 						       VR_LAST);
       tree min = stream_read_tree (ib, data_in);
       tree max = stream_read_tree (ib, data_in);
@@ -4647,7 +4640,7 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
 	  parm_vr->known = bp_unpack_value (&bp, 1);
 	  if (parm_vr->known)
 	    {
-	      parm_vr->type = streamer_read_enum (ib, value_range_type,
+	      parm_vr->type = streamer_read_enum (ib, value_range_kind,
 						  VR_LAST);
 	      parm_vr->min = streamer_read_wide_int (ib);
 	      parm_vr->max = streamer_read_wide_int (ib);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 55e10cf0f27..8a53bb89f3f 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -160,7 +160,7 @@ struct GTY(()) ipa_vr
 {
   /* The data fields below are valid only if known is true.  */
   bool known;
-  enum value_range_type type;
+  enum value_range_kind type;
   wide_int min;
   wide_int max;
 };
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index 69c5f7b28ae..66e780d635a 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -721,7 +721,7 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
 		if (TREE_CODE (tmp_var) != SSA_NAME)
 		  return false;
 		wide_int var_min, var_max;
-		value_range_type vr_type = get_range_info (tmp_var, &var_min,
+		value_range_kind vr_type = get_range_info (tmp_var, &var_min,
 							   &var_max);
 		wide_int var_nonzero = get_nonzero_bits (tmp_var);
 		signop sgn = TYPE_SIGN (itype);
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index f7cc034b26e..33224a53629 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -882,25 +882,27 @@ simplify_stmt_for_jump_threading (gimple *stmt,
 	return NULL_TREE;
 
       value_range *vr = x_vr_values->get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  size_t i, j;
 
-	  find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+	  find_case_label_range (switch_stmt, vr->min (), vr->max (), &i, &j);
 
 	  if (i == j)
 	    {
 	      tree label = gimple_switch_label (switch_stmt, i);
+	      tree singleton;
 
 	      if (CASE_HIGH (label) != NULL_TREE
-		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
-		     && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
-		  : (tree_int_cst_equal (CASE_LOW (label), vr->min)
-		     && tree_int_cst_equal (vr->min, vr->max)))
+		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min ()) <= 0
+		     && tree_int_cst_compare (CASE_HIGH (label), vr->max ()) >= 0)
+		  : ((singleton = vr->singleton_p ())
+		     && tree_int_cst_equal (CASE_LOW (label), singleton)))
 		return label;
 
 	      if (i > j)
@@ -908,7 +910,7 @@ simplify_stmt_for_jump_threading (gimple *stmt,
 	    }
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->kind () == VR_ANTI_RANGE)
           {
             unsigned n = gimple_switch_num_labels (switch_stmt);
             tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -917,10 +919,10 @@ simplify_stmt_for_jump_threading (gimple *stmt,
             /* The default label will be taken only if the anti-range of the
                operand is entirely outside the bounds of all the (non-default)
                case labels.  */
-            if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+            if (tree_int_cst_compare (vr->min (), CASE_LOW (min_label)) <= 0
                 && (CASE_HIGH (max_label) != NULL_TREE
-                    ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
-                    : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+                    ? tree_int_cst_compare (vr->max (), CASE_HIGH (max_label)) >= 0
+                    : tree_int_cst_compare (vr->max (), CASE_LOW (max_label)) >= 0))
             return gimple_switch_label (switch_stmt, 0);
           }
 	return NULL_TREE;
@@ -936,11 +938,12 @@ simplify_stmt_for_jump_threading (gimple *stmt,
 	{
 	  edge dummy_e;
 	  tree dummy_tree;
-	  value_range new_vr = VR_INITIALIZER;
+	  value_range new_vr;
 	  x_vr_values->extract_range_from_stmt (stmt, &dummy_e,
 					      &dummy_tree, &new_vr);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  tree singleton;
+	  if ((singleton = new_vr.singleton_p ()))
+	    return singleton;
 	}
     }
   return NULL;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 7b6c91ca6da..e2bc936ed52 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -353,7 +353,7 @@ determine_value_range (struct loop *loop, tree type, tree var, mpz_t off,
   mpz_t minm, maxm;
   basic_block bb;
   wide_int minv, maxv;
-  enum value_range_type rtype = VR_VARYING;
+  enum value_range_kind rtype = VR_VARYING;
 
   /* If the expression is a constant, we know its value exactly.  */
   if (integer_zerop (var))
@@ -4673,7 +4673,7 @@ scev_var_range_cant_overflow (tree var, tree step, struct loop *loop)
 {
   tree type;
   wide_int minv, maxv, diff, step_wi;
-  enum value_range_type rtype;
+  enum value_range_kind rtype;
 
   if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
     return false;
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 3fa5ef56f38..2db2823553b 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -1200,7 +1200,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
       else if (TREE_CODE (bound) == SSA_NAME)
 	{
 	  wide_int minbound, maxbound;
-	  value_range_type rng = get_range_info (bound, &minbound, &maxbound);
+	  value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
 	  if (rng == VR_RANGE)
 	    {
 	      /* For a bound in a known range, adjust the range determined
@@ -1856,7 +1856,7 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
     cntrange[0] = cntrange[1] = wi::to_wide (cnt);
   else if (TREE_CODE (cnt) == SSA_NAME)
     {
-      enum value_range_type rng = get_range_info (cnt, cntrange, cntrange + 1);
+      enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
       if (rng == VR_RANGE)
 	;
       else if (rng == VR_ANTI_RANGE)
@@ -3682,7 +3682,7 @@ strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh)
 			   if we don't have anything better.  */
 			wide_int min, max;
 			tree type = TREE_TYPE (lhs);
-			enum value_range_type vr
+			enum value_range_kind vr
 			  = get_range_info (lhs, &min, &max);
 			if (vr == VR_VARYING
 			    || (vr == VR_RANGE
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index a2304493495..0b1f9733fdd 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -166,7 +166,7 @@ record_temporary_equivalences_from_phis (edge e,
 	     away in the VR stack.  */
 	  vr_values *vr_values = evrp_range_analyzer->get_vr_values ();
 	  value_range *new_vr = vr_values->allocate_value_range ();
-	  memset (new_vr, 0, sizeof (value_range));
+	  *new_vr = value_range ();
 
 	  /* There are three cases to consider:
 
@@ -179,7 +179,7 @@ record_temporary_equivalences_from_phis (edge e,
 	       Otherwise set NEW_VR to varying.  This may be overly
 	       conservative.  */
 	  if (TREE_CODE (src) == SSA_NAME)
-	    copy_value_range (new_vr, vr_values->get_value_range (src));
+	    new_vr->deep_copy (vr_values->get_value_range (src));
 	  else if (TREE_CODE (src) == INTEGER_CST)
 	    set_value_range_to_value (new_vr, src,  NULL);
 	  else
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 6cce43be593..66b2941fbf5 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -331,7 +331,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
    NAME.  */
 
 void
-set_range_info_raw (tree name, enum value_range_type range_type,
+set_range_info_raw (tree name, enum value_range_kind range_type,
 		    const wide_int_ref &min, const wide_int_ref &max)
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
@@ -372,7 +372,7 @@ set_range_info_raw (tree name, enum value_range_type range_type,
    NAME while making sure we don't store useless range info.  */
 
 void
-set_range_info (tree name, enum value_range_type range_type,
+set_range_info (tree name, enum value_range_kind range_type,
 		const wide_int_ref &min, const wide_int_ref &max)
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
@@ -397,11 +397,11 @@ set_range_info (tree name, enum value_range_type range_type,
 }
 
 
-/* Gets range information MIN, MAX and returns enum value_range_type
-   corresponding to tree ssa_name NAME.  enum value_range_type returned
+/* Gets range information MIN, MAX and returns enum value_range_kind
+   corresponding to tree ssa_name NAME.  enum value_range_kind returned
    is used to determine if MIN and MAX are valid values.  */
 
-enum value_range_type
+enum value_range_kind
 get_range_info (const_tree name, wide_int *min, wide_int *max)
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
@@ -727,7 +727,7 @@ duplicate_ssa_name_ptr_info (tree name, struct ptr_info_def *ptr_info)
 /* Creates a duplicate of the range_info_def at RANGE_INFO of type
    RANGE_TYPE for use by the SSA name NAME.  */
 void
-duplicate_ssa_name_range_info (tree name, enum value_range_type range_type,
+duplicate_ssa_name_range_info (tree name, enum value_range_kind range_type,
 			       struct range_info_def *range_info)
 {
   struct range_info_def *new_range_info;
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index d39f3969436..18a001a5461 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -67,13 +67,13 @@ struct GTY ((variable_size)) range_info_def {
     if (VAR)
 
 /* Sets the value range to SSA.  */
-extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
+extern void set_range_info (tree, enum value_range_kind, const wide_int_ref &,
 			    const wide_int_ref &);
-extern void set_range_info_raw (tree, enum value_range_type,
+extern void set_range_info_raw (tree, enum value_range_kind,
 				const wide_int_ref &,
 				const wide_int_ref &);
 /* Gets the value range from SSA.  */
-extern enum value_range_type get_range_info (const_tree, wide_int *,
+extern enum value_range_kind get_range_info (const_tree, wide_int *,
 					     wide_int *);
 extern void set_nonzero_bits (tree, const wide_int_ref &);
 extern wide_int get_nonzero_bits (const_tree);
@@ -97,7 +97,7 @@ extern bool get_ptr_nonnull (const_tree);
 extern tree copy_ssa_name_fn (struct function *, tree, gimple *);
 extern void duplicate_ssa_name_ptr_info (tree, struct ptr_info_def *);
 extern tree duplicate_ssa_name_fn (struct function *, tree, gimple *);
-extern void duplicate_ssa_name_range_info (tree, enum value_range_type,
+extern void duplicate_ssa_name_range_info (tree, enum value_range_kind,
 					   struct range_info_def *);
 extern void reset_flow_sensitive_info (tree);
 extern void reset_flow_sensitive_info_in_bb (basic_block);
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 7956c1326d3..2be94566270 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -53,7 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 static bool
 vect_get_range_info (tree var, wide_int *min_value, wide_int *max_value)
 {
-  value_range_type vr_type = get_range_info (var, min_value, max_value);
+  value_range_kind vr_type = get_range_info (var, min_value, max_value);
   wide_int nonzero = get_nonzero_bits (var);
   signop sgn = TYPE_SIGN (TREE_TYPE (var));
   if (intersect_range_with_nonzero_bits (vr_type, min_value, max_value,
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index cbc2ea2f26b..39588dcf31f 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -73,6 +73,218 @@ along with GCC; see the file COPYING3.  If not see
    for still active basic-blocks.  */
 static sbitmap *live;
 
+/* Initialize value_range.  */
+
+void
+value_range::set (enum value_range_kind kind, tree min, tree max,
+		  bitmap equiv)
+{
+  m_kind = kind;
+  m_min = min;
+  m_max = max;
+
+  /* Since updating the equivalence set involves deep copying the
+     bitmaps, only do it if absolutely necessary.
+
+     All equivalence bitmaps are allocated from the same obstack.  So
+     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
+  if (m_equiv == NULL
+      && equiv != NULL)
+    m_equiv = BITMAP_ALLOC (equiv->obstack);
+
+  if (equiv != m_equiv)
+    {
+      if (equiv && !bitmap_empty_p (equiv))
+	bitmap_copy (m_equiv, equiv);
+      else
+	bitmap_clear (m_equiv);
+    }
+  if (flag_checking)
+    check ();
+}
+
+value_range::value_range (value_range_kind kind, tree min, tree max,
+			  bitmap equiv)
+{
+  m_equiv = NULL;
+  set (kind, min, max, equiv);
+}
+
+/* Copy value_range in FROM into THIS while avoiding bitmap sharing.
+
+   Note: The code that avoids the bitmap sharing looks at the existing
+   this->m_equiv, so this function cannot be used to initalize an
+   object.  Use the constructors for initialization.  */
+
+void
+value_range::deep_copy (const value_range *from)
+{
+  set (from->m_kind, from->m_min, from->m_max, from->m_equiv);
+}
+
+/* Check the validity of the range.  */
+
+void
+value_range::check ()
+{
+  switch (m_kind)
+    {
+    case VR_RANGE:
+    case VR_ANTI_RANGE:
+      {
+	int cmp;
+
+	gcc_assert (m_min && m_max);
+
+	gcc_assert (!TREE_OVERFLOW_P (m_min) && !TREE_OVERFLOW_P (m_max));
+
+	/* Creating ~[-MIN, +MAX] is stupid because that would be
+	   the empty set.  */
+	if (INTEGRAL_TYPE_P (TREE_TYPE (m_min)) && m_kind == VR_ANTI_RANGE)
+	  gcc_assert (!vrp_val_is_min (m_min) || !vrp_val_is_max (m_max));
+
+	cmp = compare_values (m_min, m_max);
+	gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
+	break;
+      }
+    case VR_UNDEFINED:
+    case VR_VARYING:
+      gcc_assert (!m_min && !m_max);
+      gcc_assert (!m_equiv || bitmap_empty_p (m_equiv));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Returns TRUE if THIS == OTHER.  Ignores the equivalence bitmap if
+   IGNORE_EQUIVS is TRUE.  */
+
+bool
+value_range::equal_p (const value_range &other, bool ignore_equivs) const
+{
+ return (m_kind == other.m_kind
+	 && vrp_operand_equal_p (m_min, other.m_min)
+	 && vrp_operand_equal_p (m_max, other.m_max)
+	 && (ignore_equivs
+	     || vrp_bitmap_equal_p (m_equiv, other.m_equiv)));
+}
+
+/* Return equality while ignoring equivalence bitmap.  */
+
+bool
+value_range::ignore_equivs_equal_p (const value_range &other) const
+{
+  return equal_p (other, /*ignore_equivs=*/true);
+}
+
+bool
+value_range::operator== (const value_range &other) const
+{
+ return equal_p (other, /*ignore_equivs=*/false);
+}
+
+bool
+value_range::operator!= (const value_range &other) const
+{
+ return !(*this == other);
+}
+
+/* Return TRUE if this is a symbolic range.  */
+
+bool
+value_range::symbolic_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && (!is_gimple_min_invariant (m_min)
+	      || !is_gimple_min_invariant (m_max)));
+}
+
+/* NOTE: This is not the inverse of symbolic_p because the range
+   could also be varying or undefined.  Ideally they should be inverse
+   of each other, with varying only applying to symbolics.  Varying of
+   constants would be represented as [-MIN, +MAX].  */
+
+bool
+value_range::constant_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && TREE_CODE (m_min) == INTEGER_CST
+	  && TREE_CODE (m_max) == INTEGER_CST);
+}
+
+void
+value_range::set_undefined ()
+{
+ equiv_clear ();
+  *this = value_range (VR_UNDEFINED, NULL, NULL, NULL);
+}
+
+void
+value_range::set_varying ()
+{
+  equiv_clear ();
+  *this = value_range (VR_VARYING, NULL, NULL, NULL);
+}
+
+/* Return TRUE range may possibly contain VAL.  */
+
+bool
+value_range::may_contain_p (tree val) const
+{
+  if (varying_p ())
+    return true;
+
+  if (undefined_p ())
+    return true;
+
+  if (m_kind == VR_ANTI_RANGE)
+    {
+      int res = value_inside_range (val, m_min, m_max);
+      return res == 0 || res == -2;
+    }
+  return value_inside_range (val, m_min, m_max) != 0;
+}
+
+void
+value_range::equiv_clear ()
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+}
+
+/* If value range is a singleton, return the singleton, otherwise
+   return NULL.  Note: A singleton can be any gimple invariant, not
+   just constants.  So, [&x, &x] counts as a singleton.  */
+
+tree
+value_range::singleton_p () const
+{
+  if (m_kind == VR_RANGE
+      && vrp_operand_equal_p (m_min, m_max)
+      && is_gimple_min_invariant (m_min))
+    return m_min;
+  return NULL_TREE;
+}
+
+tree
+value_range::type () const
+{
+ /* Types are valid for VR_RANGE and VR_ANTI_RANGE, which are known to
+    have non-zero min/max.  */
+ gcc_assert (m_min);
+ return TREE_TYPE (m_min);
+}
+
+void
+value_range::dump () const
+{
+  dump_value_range (stderr, this);
+  fprintf (stderr, "\n");
+}
+
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 static bool
@@ -175,8 +387,8 @@ vrp_val_is_min (const_tree val)
 
    SGN gives the sign of the values described by the range.  */
 
-enum value_range_type
-intersect_range_with_nonzero_bits (enum value_range_type vr_type,
+enum value_range_kind
+intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
 				   wide_int *min, wide_int *max,
 				   const wide_int &nonzero_bits,
 				   signop sgn)
@@ -245,10 +457,7 @@ intersect_range_with_nonzero_bits (enum value_range_type vr_type,
 static inline void
 set_value_range_to_undefined (value_range *vr)
 {
-  vr->type = VR_UNDEFINED;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_undefined ();
 }
 
 /* Set value range VR to VR_VARYING.  */
@@ -256,67 +465,21 @@ set_value_range_to_undefined (value_range *vr)
 void
 set_value_range_to_varying (value_range *vr)
 {
-  vr->type = VR_VARYING;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_varying ();
 }
 
 /* Set value range VR to {T, MIN, MAX, EQUIV}.  */
 
 void
-set_value_range (value_range *vr, enum value_range_type t, tree min,
-		 tree max, bitmap equiv)
+set_value_range (value_range *vr, enum value_range_kind kind,
+		 tree min, tree max, bitmap equiv)
 {
-  /* Check the validity of the range.  */
-  if (flag_checking
-      && (t == VR_RANGE || t == VR_ANTI_RANGE))
-    {
-      int cmp;
-
-      gcc_assert (min && max);
-
-      gcc_assert (!TREE_OVERFLOW_P (min) && !TREE_OVERFLOW_P (max));
-
-      if (INTEGRAL_TYPE_P (TREE_TYPE (min)) && t == VR_ANTI_RANGE)
-	gcc_assert (!vrp_val_is_min (min) || !vrp_val_is_max (max));
-
-      cmp = compare_values (min, max);
-      gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
-    }
-
-  if (flag_checking
-      && (t == VR_UNDEFINED || t == VR_VARYING))
-    {
-      gcc_assert (min == NULL_TREE && max == NULL_TREE);
-      gcc_assert (equiv == NULL || bitmap_empty_p (equiv));
-    }
-
-  vr->type = t;
-  vr->min = min;
-  vr->max = max;
-
-  /* Since updating the equivalence set involves deep copying the
-     bitmaps, only do it if absolutely necessary.
-
-     All equivalence bitmaps are allocated from the same obstack.  So
-     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
-  if (vr->equiv == NULL
-      && equiv != NULL)
-    vr->equiv = BITMAP_ALLOC (equiv->obstack);
-
-  if (equiv != vr->equiv)
-    {
-      if (equiv && !bitmap_empty_p (equiv))
-	bitmap_copy (vr->equiv, equiv);
-      else
-	bitmap_clear (vr->equiv);
-    }
+  *vr = value_range (kind, min, max, equiv);
 }
 
 
-/* Set value range VR to the canonical form of {T, MIN, MAX, EQUIV}.
-   This means adjusting T, MIN and MAX representing the case of a
+/* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
+   This means adjusting VRTYPE, MIN and MAX representing the case of a
    wrapping range with MAX < MIN covering [MIN, type_max] U [type_min, MAX]
    as anti-rage ~[MAX+1, MIN-1].  Likewise for wrapping anti-ranges.
    In corner cases where MAX+1 or MIN-1 wraps this will fall back
@@ -325,18 +488,18 @@ set_value_range (value_range *vr, enum value_range_type t, tree min,
    extract ranges from var + CST op limit.  */
 
 void
-set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
-				  tree min, tree max, bitmap equiv)
+value_range::set_and_canonicalize (enum value_range_kind kind,
+				   tree min, tree max, bitmap equiv)
 {
   /* Use the canonical setters for VR_UNDEFINED and VR_VARYING.  */
-  if (t == VR_UNDEFINED)
+  if (kind == VR_UNDEFINED)
     {
-      set_value_range_to_undefined (vr);
+      set_undefined ();
       return;
     }
-  else if (t == VR_VARYING)
+  else if (kind == VR_VARYING)
     {
-      set_value_range_to_varying (vr);
+      set_varying ();
       return;
     }
 
@@ -344,7 +507,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
   if (TREE_CODE (min) != INTEGER_CST
       || TREE_CODE (max) != INTEGER_CST)
     {
-      set_value_range (vr, t, min, max, equiv);
+      set_value_range (this, kind, min, max, equiv);
       return;
     }
 
@@ -359,7 +522,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	 for VR_ANTI_RANGE empty range, so drop to varying as well.  */
       if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
 	{
-	  set_value_range_to_varying (vr);
+	  set_varying ();
 	  return;
 	}
 
@@ -373,15 +536,15 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	 to varying in this case.  */
       if (tree_int_cst_lt (max, min))
 	{
-	  set_value_range_to_varying (vr);
+	  set_varying ();
 	  return;
 	}
 
-      t = t == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
+      kind = kind == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
     }
 
   /* Anti-ranges that can be represented as ranges should be so.  */
-  if (t == VR_ANTI_RANGE)
+  if (kind == VR_ANTI_RANGE)
     {
       /* For -fstrict-enums we may receive out-of-range ranges so consider
          values < -INF and values > INF as -INF/INF as well.  */
@@ -395,7 +558,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	{
 	  /* We cannot deal with empty ranges, drop to varying.
 	     ???  This could be VR_UNDEFINED instead.  */
-	  set_value_range_to_varying (vr);
+	  set_varying ();
 	  return;
 	}
       else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
@@ -407,7 +570,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	    min = max = vrp_val_max (TREE_TYPE (min));
 	  else
 	    min = max = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
+	  kind = VR_RANGE;
 	}
       else if (is_min
 	       /* As a special exception preserve non-null ranges.  */
@@ -417,14 +580,14 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	  tree one = build_int_cst (TREE_TYPE (max), 1);
 	  min = int_const_binop (PLUS_EXPR, max, one);
 	  max = vrp_val_max (TREE_TYPE (max));
-	  t = VR_RANGE;
+	  kind = VR_RANGE;
         }
       else if (is_max)
         {
 	  tree one = build_int_cst (TREE_TYPE (min), 1);
 	  max = int_const_binop (MINUS_EXPR, min, one);
 	  min = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
+	  kind = VR_RANGE;
         }
     }
 
@@ -432,15 +595,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
      to make sure VRP iteration terminates, otherwise we can get into
      oscillations.  */
 
-  set_value_range (vr, t, min, max, equiv);
-}
-
-/* Copy value range FROM into value range TO.  */
-
-void
-copy_value_range (value_range *to, const value_range *from)
-{
-  set_value_range (to, from->type, from->min, from->max, from->equiv);
+  set_value_range (this, kind, min, max, equiv);
 }
 
 /* Set value range VR to a single value.  This function is only called
@@ -462,7 +617,7 @@ void
 set_value_range_to_nonnull (value_range *vr, tree type)
 {
   tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv);
+  set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv ());
 }
 
 
@@ -471,7 +626,7 @@ set_value_range_to_nonnull (value_range *vr, tree type)
 void
 set_value_range_to_null (value_range *vr, tree type)
 {
-  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv);
+  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv ());
 }
 
 /* Return true, if VAL1 and VAL2 are equal values for VRP purposes.  */
@@ -503,9 +658,15 @@ vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
 static inline bool
 range_is_null (const value_range *vr)
 {
-  return vr->type == VR_RANGE
-	 && integer_zerop (vr->min)
-	 && integer_zerop (vr->max);
+  return vr->null_p ();
+}
+
+static inline bool
+range_is_nonnull (const value_range *vr)
+{
+  return (vr->kind () == VR_ANTI_RANGE
+	  && vr->min () == vr->max ()
+	  && integer_zerop (vr->min ()));
 }
 
 /* Return true if max and min of VR are INTEGER_CST.  It's not necessary
@@ -514,9 +675,9 @@ range_is_null (const value_range *vr)
 bool
 range_int_cst_p (const value_range *vr)
 {
-  return (vr->type == VR_RANGE
-	  && TREE_CODE (vr->max) == INTEGER_CST
-	  && TREE_CODE (vr->min) == INTEGER_CST);
+  return (vr->kind () == VR_RANGE
+	  && TREE_CODE (vr->min ()) == INTEGER_CST
+	  && TREE_CODE (vr->max ()) == INTEGER_CST);
 }
 
 /* Return true if VR is a INTEGER_CST singleton.  */
@@ -525,16 +686,7 @@ bool
 range_int_cst_singleton_p (const value_range *vr)
 {
   return (range_int_cst_p (vr)
-	  && tree_int_cst_equal (vr->min, vr->max));
-}
-
-/* Return true if value range VR involves at least one symbol.  */
-
-bool
-symbolic_range_p (const value_range *vr)
-{
-  return (!is_gimple_min_invariant (vr->min)
-          || !is_gimple_min_invariant (vr->max));
+	  && tree_int_cst_equal (vr->min (), vr->max ()));
 }
 
 /* Return the single symbol (an SSA_NAME) contained in T if any, or NULL_TREE
@@ -849,34 +1001,22 @@ value_inside_range (tree val, tree min, tree max)
 bool
 range_includes_zero_p (const value_range *vr)
 {
-  if (vr->type == VR_VARYING)
+  if (vr->varying_p () || vr->undefined_p ())
     return true;
-
-  /* Ughh, we don't know.  We choose not to optimize.  */
-  if (vr->type == VR_UNDEFINED)
-    return true;
-
-  tree zero = build_int_cst (TREE_TYPE (vr->min), 0);
-  if (vr->type == VR_ANTI_RANGE)
-    {
-      int res = value_inside_range (zero, vr->min, vr->max);
-      return res == 0 || res == -2;
-    }
-  return value_inside_range (zero, vr->min, vr->max) != 0;
+  tree zero = build_int_cst (vr->type (), 0);
+  return vr->may_contain_p (zero);
 }
 
-/* If *VR has a value rante that is a single constant value return that,
-   otherwise return NULL_TREE.  */
+/* If *VR has a value range that is a single constant value return that,
+   otherwise return NULL_TREE.
+
+   ?? This actually returns TRUE for [&x, &x], so perhaps "constant"
+   is not the best name.  */
 
 tree
 value_range_constant_singleton (const value_range *vr)
 {
-  if (vr->type == VR_RANGE
-      && vrp_operand_equal_p (vr->min, vr->max)
-      && is_gimple_min_invariant (vr->min))
-    return vr->min;
-
-  return NULL_TREE;
+  return vr->singleton_p ();
 }
 
 /* Value range wrapper for wide_int_range_set_zero_nonzero_bits.
@@ -899,8 +1039,8 @@ vrp_set_zero_nonzero_bits (const tree expr_type,
       return false;
     }
   wide_int_range_set_zero_nonzero_bits (TYPE_SIGN (expr_type),
-					wi::to_wide (vr->min),
-					wi::to_wide (vr->max),
+					wi::to_wide (vr->min ()),
+					wi::to_wide (vr->max ()),
 					*may_be_nonzero, *must_be_nonzero);
   return true;
 }
@@ -914,40 +1054,36 @@ static bool
 ranges_from_anti_range (const value_range *ar,
 			value_range *vr0, value_range *vr1)
 {
-  tree type = TREE_TYPE (ar->min);
+  tree type = ar->type ();
 
-  vr0->type = VR_UNDEFINED;
-  vr1->type = VR_UNDEFINED;
+  vr0->set_undefined ();
+  vr1->set_undefined ();
 
   /* As a future improvement, we could handle ~[0, A] as: [-INF, -1] U
      [A+1, +INF].  Not sure if this helps in practice, though.  */
 
-  if (ar->type != VR_ANTI_RANGE
-      || TREE_CODE (ar->min) != INTEGER_CST
-      || TREE_CODE (ar->max) != INTEGER_CST
+  if (ar->kind () != VR_ANTI_RANGE
+      || TREE_CODE (ar->min ()) != INTEGER_CST
+      || TREE_CODE (ar->max ()) != INTEGER_CST
       || !vrp_val_min (type)
       || !vrp_val_max (type))
     return false;
 
-  if (!vrp_val_is_min (ar->min))
-    {
-      vr0->type = VR_RANGE;
-      vr0->min = vrp_val_min (type);
-      vr0->max = wide_int_to_tree (type, wi::to_wide (ar->min) - 1);
-    }
-  if (!vrp_val_is_max (ar->max))
-    {
-      vr1->type = VR_RANGE;
-      vr1->min = wide_int_to_tree (type, wi::to_wide (ar->max) + 1);
-      vr1->max = vrp_val_max (type);
-    }
-  if (vr0->type == VR_UNDEFINED)
+  if (!vrp_val_is_min (ar->min ()))
+    *vr0 = value_range (VR_RANGE,
+			vrp_val_min (type),
+			wide_int_to_tree (type, wi::to_wide (ar->min ()) - 1));
+  if (!vrp_val_is_max (ar->max ()))
+    *vr1 = value_range (VR_RANGE,
+			wide_int_to_tree (type, wi::to_wide (ar->max ()) + 1),
+			vrp_val_max (type));
+  if (vr0->undefined_p ())
     {
       *vr0 = *vr1;
-      vr1->type = VR_UNDEFINED;
+      vr1->set_undefined ();
     }
 
-  return vr0->type != VR_UNDEFINED;
+  return !vr0->undefined_p ();
 }
 
 /* Extract the components of a value range into a pair of wide ints in
@@ -961,13 +1097,11 @@ extract_range_into_wide_ints (const value_range *vr,
 			      signop sign, unsigned prec,
 			      wide_int &wmin, wide_int &wmax)
 {
-  if ((vr->type == VR_RANGE
-       || vr->type == VR_ANTI_RANGE)
-      && TREE_CODE (vr->min) == INTEGER_CST
-      && TREE_CODE (vr->max) == INTEGER_CST)
+  gcc_assert (vr->kind () != VR_ANTI_RANGE || vr->symbolic_p ());
+  if (range_int_cst_p (vr))
     {
-      wmin = wi::to_wide (vr->min);
-      wmax = wi::to_wide (vr->max);
+      wmin = wi::to_wide (vr->min ());
+      wmax = wi::to_wide (vr->max ());
     }
   else
     {
@@ -994,14 +1128,15 @@ extract_range_from_multiplicative_op (value_range *vr,
 	      || code == ROUND_DIV_EXPR
 	      || code == RSHIFT_EXPR
 	      || code == LSHIFT_EXPR);
-  gcc_assert (vr0->type == VR_RANGE && vr0->type == vr1->type);
+  gcc_assert (vr0->kind () == VR_RANGE
+	      && vr0->kind () == vr1->kind ());
 
-  tree type = TREE_TYPE (vr0->min);
+  tree type = vr0->type ();
   wide_int res_lb, res_ub;
-  wide_int vr0_lb = wi::to_wide (vr0->min);
-  wide_int vr0_ub = wi::to_wide (vr0->max);
-  wide_int vr1_lb = wi::to_wide (vr1->min);
-  wide_int vr1_ub = wi::to_wide (vr1->max);
+  wide_int vr0_lb = wi::to_wide (vr0->min ());
+  wide_int vr0_ub = wi::to_wide (vr0->max ());
+  wide_int vr1_lb = wi::to_wide (vr1->min ());
+  wide_int vr1_ub = wi::to_wide (vr1->max ());
   bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
   bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
   unsigned prec = TYPE_PRECISION (type);
@@ -1010,9 +1145,9 @@ extract_range_from_multiplicative_op (value_range *vr,
 					 code, TYPE_SIGN (type), prec,
 					 vr0_lb, vr0_ub, vr1_lb, vr1_ub,
 					 overflow_undefined, overflow_wraps))
-    set_and_canonicalize_value_range (vr, VR_RANGE,
-				      wide_int_to_tree (type, res_lb),
-				      wide_int_to_tree (type, res_ub), NULL);
+    vr->set_and_canonicalize (VR_RANGE,
+			      wide_int_to_tree (type, res_lb),
+			      wide_int_to_tree (type, res_ub), NULL);
   else
     set_value_range_to_varying (vr);
 }
@@ -1114,8 +1249,6 @@ set_value_range_with_overflow (value_range &vr,
 {
   const signop sgn = TYPE_SIGN (type);
   const unsigned int prec = TYPE_PRECISION (type);
-  vr.type = VR_RANGE;
-  vr.equiv = NULL;
 
   /* For one bit precision if max < min, then the swapped
      range covers all values.  */
@@ -1133,10 +1266,18 @@ set_value_range_with_overflow (value_range &vr,
       wide_int tmax = wide_int::from (wmax, prec, sgn);
       if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE))
 	{
-	  /* No overflow or both overflow or underflow.  The
-	     range kind stays VR_RANGE.  */
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  /* If the limits are swapped, we wrapped around and cover
+	     the entire range.  We have a similar check at the end of
+	     extract_range_from_binary_expr_1.  */
+	  if (wi::gt_p (tmin, tmax, sgn))
+	    vr.set_varying ();
+	  else
+	    /* No overflow or both overflow or underflow.  The
+	       range kind stays VR_RANGE.  */
+	    vr = value_range (VR_RANGE,
+			      wide_int_to_tree (type, tmin),
+			      wide_int_to_tree (type, tmax));
+	  return;
 	}
       else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
 	       || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
@@ -1145,7 +1286,6 @@ set_value_range_with_overflow (value_range &vr,
 	     changes to VR_ANTI_RANGE.  */
 	  bool covers = false;
 	  wide_int tem = tmin;
-	  vr.type = VR_ANTI_RANGE;
 	  tmin = tmax + 1;
 	  if (wi::cmp (tmin, tmax, sgn) < 0)
 	    covers = true;
@@ -1160,8 +1300,10 @@ set_value_range_with_overflow (value_range &vr,
 	      set_value_range_to_varying (&vr);
 	      return;
 	    }
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  vr = value_range (VR_ANTI_RANGE,
+			    wide_int_to_tree (type, tmin),
+			    wide_int_to_tree (type, tmax));
+	  return;
 	}
       else
 	{
@@ -1176,19 +1318,21 @@ set_value_range_with_overflow (value_range &vr,
 	 value.  */
       wide_int type_min = wi::min_value (prec, sgn);
       wide_int type_max = wi::max_value (prec, sgn);
+      tree min, max;
       if (min_ovf == wi::OVF_UNDERFLOW)
-	vr.min = wide_int_to_tree (type, type_min);
+	min = wide_int_to_tree (type, type_min);
       else if (min_ovf == wi::OVF_OVERFLOW)
-	vr.min = wide_int_to_tree (type, type_max);
+	min = wide_int_to_tree (type, type_max);
       else
-	vr.min = wide_int_to_tree (type, wmin);
+	min = wide_int_to_tree (type, wmin);
 
       if (max_ovf == wi::OVF_UNDERFLOW)
-	vr.max = wide_int_to_tree (type, type_min);
+	max = wide_int_to_tree (type, type_min);
       else if (max_ovf == wi::OVF_OVERFLOW)
-	vr.max = wide_int_to_tree (type, type_max);
+	max = wide_int_to_tree (type, type_max);
       else
-	vr.max = wide_int_to_tree (type, wmax);
+	max = wide_int_to_tree (type, wmax);
+      vr = value_range (VR_RANGE, min, max);
     }
 }
 
@@ -1205,8 +1349,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
   signop sign = TYPE_SIGN (expr_type);
   unsigned int prec = TYPE_PRECISION (expr_type);
   value_range vr0 = *vr0_, vr1 = *vr1_;
-  value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
-  enum value_range_type type;
+  value_range vrtem0, vrtem1;
+  enum value_range_kind type;
   tree min = NULL_TREE, max = NULL_TREE;
   int cmp;
 
@@ -1242,7 +1386,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
     }
 
   /* If both ranges are UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED && vr1.type == VR_UNDEFINED)
+  if (vr0.undefined_p () && vr1.undefined_p ())
     {
       set_value_range_to_undefined (vr);
       return;
@@ -1251,19 +1395,16 @@ extract_range_from_binary_expr_1 (value_range *vr,
      code.  At some point we may want to special-case operations that
      have UNDEFINED result for all or some value-ranges of the not UNDEFINED
      operand.  */
-  else if (vr0.type == VR_UNDEFINED)
+  else if (vr0.undefined_p ())
     set_value_range_to_varying (&vr0);
-  else if (vr1.type == VR_UNDEFINED)
+  else if (vr1.undefined_p ())
     set_value_range_to_varying (&vr1);
 
   /* We get imprecise results from ranges_from_anti_range when
      code is EXACT_DIV_EXPR.  We could mask out bits in the resulting
-     range, but then we also need to hack up vrp_meet.  It's just
+     range, but then we also need to hack up vrp_union.  It's just
      easier to special case when vr0 is ~[0,0] for EXACT_DIV_EXPR.  */
-  if (code == EXACT_DIV_EXPR
-      && vr0.type == VR_ANTI_RANGE
-      && vr0.min == vr0.max
-      && integer_zerop (vr0.min))
+  if (code == EXACT_DIV_EXPR && range_is_nonnull (&vr0))
     {
       set_value_range_to_nonnull (vr, expr_type);
       return;
@@ -1271,36 +1412,35 @@ extract_range_from_binary_expr_1 (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express ~[] op X as ([]' op X) U ([]'' op X).  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.kind () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
-	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
-					    &vrtem1, vr1_);
-	  vrp_meet (vr, &vrres);
+	  value_range vrres;
+	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,					    &vrtem1, vr1_);
+	  vr->union_ (&vrres);
 	}
       return;
     }
   /* Likewise for X op ~[].  */
-  if (vr1.type == VR_ANTI_RANGE
+  if (vr1.kind () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr1, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres;
 	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
 					    vr0_, &vrtem1);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
 
   /* The type of the resulting value range defaults to VR0.TYPE.  */
-  type = vr0.type;
+  type = vr0.kind ();
 
   /* Refuse to operate on VARYING ranges, ranges of different kinds
      and symbolic ranges.  As an exception, we allow BIT_{AND,IOR}
@@ -1323,11 +1463,11 @@ extract_range_from_binary_expr_1 (value_range *vr,
       && code != MINUS_EXPR
       && code != RSHIFT_EXPR
       && code != POINTER_PLUS_EXPR
-      && (vr0.type == VR_VARYING
-	  || vr1.type == VR_VARYING
-	  || vr0.type != vr1.type
-	  || symbolic_range_p (&vr0)
-	  || symbolic_range_p (&vr1)))
+      && (vr0.varying_p ()
+	  || vr1.varying_p ()
+	  || vr0.kind () != vr1.kind ()
+	  || vr0.symbolic_p ()
+	  || vr1.symbolic_p ()))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1385,24 +1525,20 @@ extract_range_from_binary_expr_1 (value_range *vr,
       /* This will normalize things such that calculating
 	 [0,0] - VR_VARYING is not dropped to varying, but is
 	 calculated as [MIN+1, MAX].  */
-      if (vr0.type == VR_VARYING)
-	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = vrp_val_min (expr_type);
-	  vr0.max = vrp_val_max (expr_type);
-	}
-      if (vr1.type == VR_VARYING)
-	{
-	  vr1.type = VR_RANGE;
-	  vr1.min = vrp_val_min (expr_type);
-	  vr1.max = vrp_val_max (expr_type);
-	}
+      if (vr0.varying_p ())
+	vr0 = value_range (VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type), vr0.equiv ());
+      if (vr1.varying_p ())
+	vr1 = value_range (VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type), vr0.equiv ());
 
       const bool minus_p = (code == MINUS_EXPR);
-      tree min_op0 = vr0.min;
-      tree min_op1 = minus_p ? vr1.max : vr1.min;
-      tree max_op0 = vr0.max;
-      tree max_op1 = minus_p ? vr1.min : vr1.max;
+      tree min_op0 = vr0.min ();
+      tree min_op1 = minus_p ? vr1.max () : vr1.min ();
+      tree max_op0 = vr0.max ();
+      tree max_op1 = minus_p ? vr1.min () : vr1.max ();
       tree sym_min_op0 = NULL_TREE;
       tree sym_min_op1 = NULL_TREE;
       tree sym_max_op0 = NULL_TREE;
@@ -1415,7 +1551,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
 	 single-symbolic ranges, try to compute the precise resulting range,
 	 but only if we know that this resulting range will also be constant
 	 or single-symbolic.  */
-      if (vr0.type == VR_RANGE && vr1.type == VR_RANGE
+      if (vr0.kind () == VR_RANGE && vr1.kind () == VR_RANGE
 	  && (TREE_CODE (min_op0) == INTEGER_CST
 	      || (sym_min_op0
 		  = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
@@ -1455,21 +1591,19 @@ extract_range_from_binary_expr_1 (value_range *vr,
 	  /* Adjust the range for possible overflow.  */
 	  set_value_range_with_overflow (*vr, expr_type,
 					 wmin, wmax, min_ovf, max_ovf);
-	  if (vr->type == VR_VARYING)
+	  if (vr->varying_p ())
 	    return;
 
 	  /* Build the symbolic bounds if needed.  */
-	  adjust_symbolic_bound (vr->min, code, expr_type,
+	  min = vr->min ();
+	  max = vr->max ();
+	  adjust_symbolic_bound (min, code, expr_type,
 				 sym_min_op0, sym_min_op1,
 				 neg_min_op0, neg_min_op1);
-	  adjust_symbolic_bound (vr->max, code, expr_type,
+	  adjust_symbolic_bound (max, code, expr_type,
 				 sym_max_op0, sym_max_op1,
 				 neg_max_op0, neg_max_op1);
-	  /* ?? It would probably be cleaner to eliminate min/max/type
-	     entirely and hold these values in VR directly.  */
-	  min = vr->min;
-	  max = vr->max;
-	  type = vr->type;
+	  type = vr->kind ();
 	}
       else
 	{
@@ -1522,20 +1656,19 @@ extract_range_from_binary_expr_1 (value_range *vr,
     {
       if (range_int_cst_p (&vr1)
 	  && !wide_int_range_shift_undefined_p (prec,
-						wi::to_wide (vr1.min),
-						wi::to_wide (vr1.max)))
+						wi::to_wide (vr1.min ()),
+						wi::to_wide (vr1.max ())))
 	{
 	  if (code == RSHIFT_EXPR)
 	    {
 	      /* Even if vr0 is VARYING or otherwise not usable, we can derive
 		 useful ranges just from the shift count.  E.g.
 		 x >> 63 for signed 64-bit x is always [-1, 0].  */
-	      if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
-		{
-		  vr0.type = type = VR_RANGE;
-		  vr0.min = vrp_val_min (expr_type);
-		  vr0.max = vrp_val_max (expr_type);
-		}
+	      if (vr0.kind () != VR_RANGE || vr0.symbolic_p ())
+		vr0 = value_range (VR_RANGE,
+				   vrp_val_min (expr_type),
+				   vrp_val_max (expr_type),
+				   vr0.equiv ());
 	      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
 	      return;
 	    }
@@ -1544,17 +1677,16 @@ extract_range_from_binary_expr_1 (value_range *vr,
 	    {
 	      wide_int res_lb, res_ub;
 	      if (wide_int_range_lshift (res_lb, res_ub, sign, prec,
-					 wi::to_wide (vr0.min),
-					 wi::to_wide (vr0.max),
-					 wi::to_wide (vr1.min),
-					 wi::to_wide (vr1.max),
+					 wi::to_wide (vr0.min ()),
+					 wi::to_wide (vr0.max ()),
+					 wi::to_wide (vr1.min ()),
+					 wi::to_wide (vr1.max ()),
 					 TYPE_OVERFLOW_UNDEFINED (expr_type),
 					 TYPE_OVERFLOW_WRAPS (expr_type)))
 		{
 		  min = wide_int_to_tree (expr_type, res_lb);
 		  max = wide_int_to_tree (expr_type, res_ub);
-		  set_and_canonicalize_value_range (vr, VR_RANGE,
-						    min, max, NULL);
+		  vr->set_and_canonicalize (VR_RANGE, min, max, NULL);
 		  return;
 		}
 	    }
@@ -1605,11 +1737,11 @@ extract_range_from_binary_expr_1 (value_range *vr,
 		       wide_int_to_tree (expr_type, wmax), NULL);
       if (extra_range_p)
 	{
-	  value_range extra_range = VR_INITIALIZER;
+	  value_range extra_range;
 	  set_value_range (&extra_range, VR_RANGE,
 			   wide_int_to_tree (expr_type, extra_min),
 			   wide_int_to_tree (expr_type, extra_max), NULL);
-	  vrp_meet (vr, &extra_range);
+	  vr->union_ (&extra_range);
 	}
       return;
     }
@@ -1742,7 +1874,8 @@ extract_range_from_unary_expr (value_range *vr,
 {
   signop sign = TYPE_SIGN (type);
   unsigned int prec = TYPE_PRECISION (type);
-  value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+  value_range vr0 = *vr0_;
+  value_range vrtem0, vrtem1;
 
   /* VRP only operates on integral and pointer types.  */
   if (!(INTEGRAL_TYPE_P (op0_type)
@@ -1755,7 +1888,7 @@ extract_range_from_unary_expr (value_range *vr,
     }
 
   /* If VR0 is UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED)
+  if (vr0.undefined_p ())
     {
       set_value_range_to_undefined (vr);
       return;
@@ -1765,14 +1898,14 @@ extract_range_from_unary_expr (value_range *vr,
   if (code == PAREN_EXPR || code == OBJ_TYPE_REF)
     {
       /* PAREN_EXPR and OBJ_TYPE_REF are simple copies.  */
-      copy_value_range (vr, &vr0);
+      vr->deep_copy (&vr0);
       return;
     }
   else if (code == NEGATE_EXPR)
     {
       /* -X is simply 0 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range zero = VR_INITIALIZER;
+      value_range zero;
       set_value_range_to_value (&zero, build_int_cst (type, 0), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR, type, &zero, &vr0);
       return;
@@ -1781,7 +1914,7 @@ extract_range_from_unary_expr (value_range *vr,
     {
       /* ~X is simply -1 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range minusone = VR_INITIALIZER;
+      value_range minusone;
       set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
 					type, &minusone, &vr0);
@@ -1790,16 +1923,16 @@ extract_range_from_unary_expr (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express op ~[]  as (op []') U (op []'').  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.kind () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_unary_expr (vr, code, type, &vrtem0, op0_type);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres;
 	  extract_range_from_unary_expr (&vrres, code, type,
 					 &vrtem1, op0_type);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
@@ -1831,8 +1964,8 @@ extract_range_from_unary_expr (value_range *vr,
 	 pointer anti-ranges.  Any remaining anti-ranges at this point
 	 will be integer conversions from SSA names that will be
 	 normalized into VARYING.  For instance: ~[x_55, x_55].  */
-      gcc_assert (vr0.type != VR_ANTI_RANGE
-		  || TREE_CODE (vr0.min) != INTEGER_CST);
+      gcc_assert (vr0.kind () != VR_ANTI_RANGE
+		  || TREE_CODE (vr0.min ()) != INTEGER_CST);
 
       /* NOTES: Previously we were returning VARYING for all symbolics, but
 	 we can do better by treating them as [-MIN, +MAX].  For
@@ -1855,7 +1988,7 @@ extract_range_from_unary_expr (value_range *vr,
 	{
 	  tree min = wide_int_to_tree (outer_type, wmin);
 	  tree max = wide_int_to_tree (outer_type, wmax);
-	  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
+	  vr->set_and_canonicalize (VR_RANGE, min, max, NULL);
 	}
       else
 	set_value_range_to_varying (vr);
@@ -1897,39 +2030,39 @@ dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
-  else if (vr->type == VR_UNDEFINED)
+  else if (vr->undefined_p ())
     fprintf (file, "UNDEFINED");
-  else if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
+  else if (vr->kind () == VR_RANGE || vr->kind () == VR_ANTI_RANGE)
     {
-      tree type = TREE_TYPE (vr->min);
+      tree type = TREE_TYPE (vr->min ());
 
-      fprintf (file, "%s[", (vr->type == VR_ANTI_RANGE) ? "~" : "");
+      fprintf (file, "%s[", (vr->kind () == VR_ANTI_RANGE) ? "~" : "");
 
       if (INTEGRAL_TYPE_P (type)
 	  && !TYPE_UNSIGNED (type)
-	  && vrp_val_is_min (vr->min))
+	  && vrp_val_is_min (vr->min ()))
 	fprintf (file, "-INF");
       else
-	print_generic_expr (file, vr->min);
+	print_generic_expr (file, vr->min ());
 
       fprintf (file, ", ");
 
       if (INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_max (vr->max))
+	  && vrp_val_is_max (vr->max ()))
 	fprintf (file, "+INF");
       else
-	print_generic_expr (file, vr->max);
+	print_generic_expr (file, vr->max ());
 
       fprintf (file, "]");
 
-      if (vr->equiv)
+      if (vr->equiv ())
 	{
 	  bitmap_iterator bi;
 	  unsigned i, c = 0;
 
 	  fprintf (file, "  EQUIVALENCES: { ");
 
-	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv, 0, i, bi)
+	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv (), 0, i, bi)
 	    {
 	      print_generic_expr (file, ssa_name (i));
 	      fprintf (file, " ");
@@ -1939,7 +2072,7 @@ dump_value_range (FILE *file, const value_range *vr)
 	  fprintf (file, "} (%u elements)", c);
 	}
     }
-  else if (vr->type == VR_VARYING)
+  else if (vr->varying_p ())
     fprintf (file, "VARYING");
   else
     fprintf (file, "INVALID RANGE");
@@ -1951,14 +2084,7 @@ dump_value_range (FILE *file, const value_range *vr)
 DEBUG_FUNCTION void
 debug_value_range (const value_range *vr)
 {
-  dump_value_range (stderr, vr);
-  fprintf (stderr, "\n");
-}
-
-void
-value_range::dump () const
-{
-  debug_value_range (this);
+  vr->dump ();
 }
 
 
@@ -4202,14 +4328,14 @@ vrp_prop::check_array_ref (location_t location, tree ref,
   if (TREE_CODE (low_sub) == SSA_NAME)
     {
       vr = get_value_range (low_sub);
-      if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
+      if (!vr->undefined_p () && !vr->varying_p ())
         {
-          low_sub = vr->type == VR_RANGE ? vr->max : vr->min;
-          up_sub = vr->type == VR_RANGE ? vr->min : vr->max;
+          low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
+          up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
         }
     }
 
-  if (vr && vr->type == VR_ANTI_RANGE)
+  if (vr && vr->kind () == VR_ANTI_RANGE)
     {
       if (up_bound
 	  && TREE_CODE (up_sub) == INTEGER_CST
@@ -4337,21 +4463,20 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
 	break;
 
       vr = get_value_range (varoff);
-      if (!vr || vr->type == VR_UNDEFINED || !vr->min || !vr->max)
+      if (!vr || vr->undefined_p () || vr->varying_p ())
 	break;
 
-      if (TREE_CODE (vr->min) != INTEGER_CST
-          || TREE_CODE (vr->max) != INTEGER_CST)
+      if (!vr->constant_p ())
         break;
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
-	  if (tree_int_cst_lt (vr->min, vr->max))
+	  if (tree_int_cst_lt (vr->min (), vr->max ()))
 	    {
 	      offset_int min
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min ()));
 	      offset_int max
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max ()));
 	      if (min < max)
 		{
 		  offrange[0] += min;
@@ -5123,8 +5248,8 @@ find_case_label_range (gswitch *stmt, tree min, tree max, size_t *min_idx,
 enum ssa_prop_result
 vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 {
-  value_range vr = VR_INITIALIZER;
   tree lhs = gimple_get_lhs (stmt);
+  value_range vr;
   extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr);
 
   if (*output_p)
@@ -5140,7 +5265,7 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 	      fprintf (dump_file, "\n");
 	    }
 
-	  if (vr.type == VR_VARYING)
+	  if (vr.varying_p ())
 	    return SSA_PROP_VARYING;
 
 	  return SSA_PROP_INTERESTING;
@@ -5193,17 +5318,14 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 		   SSA_PROP_NOT_INTERESTING.  If there are no
 		   {REAL,IMAG}PART_EXPR uses at all,
 		   return SSA_PROP_VARYING.  */
-		value_range new_vr = VR_INITIALIZER;
+		value_range new_vr;
 		extract_range_basic (&new_vr, use_stmt);
 		const value_range *old_vr = get_value_range (use_lhs);
-		if (old_vr->type != new_vr.type
-		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
-		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
-		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
+		if (*old_vr != new_vr)
 		  res = SSA_PROP_INTERESTING;
 		else
 		  res = SSA_PROP_NOT_INTERESTING;
-		BITMAP_FREE (new_vr.equiv);
+		new_vr.equiv_clear ();
 		if (res == SSA_PROP_INTERESTING)
 		  {
 		    *output_p = lhs;
@@ -5231,9 +5353,9 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
    possible such range.  The resulting range is not canonicalized.  */
 
 static void
-union_ranges (enum value_range_type *vr0type,
+union_ranges (enum value_range_kind *vr0type,
 	      tree *vr0min, tree *vr0max,
-	      enum value_range_type vr1type,
+	      enum value_range_kind vr1type,
 	      tree vr1min, tree vr1max)
 {
   bool mineq = vrp_operand_equal_p (*vr0min, vr1min);
@@ -5502,9 +5624,9 @@ give_up:
    possible such range.  The resulting range is not canonicalized.  */
 
 static void
-intersect_ranges (enum value_range_type *vr0type,
+intersect_ranges (enum value_range_kind *vr0type,
 		  tree *vr0min, tree *vr0max,
-		  enum value_range_type vr1type,
+		  enum value_range_kind vr1type,
 		  tree vr1min, tree vr1max)
 {
   bool mineq = vrp_operand_equal_p (*vr0min, vr1min);
@@ -5814,33 +5936,29 @@ intersect_ranges (enum value_range_type *vr0type,
       *vr0min = vr1min;
       *vr0max = vr1max;
     }
-
-  return;
 }
 
 
 /* Intersect the two value-ranges *VR0 and *VR1 and store the result
    in *VR0.  This may not be the smallest possible such range.  */
 
-static void
-vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
+void
+value_range::intersect_helper (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
   /* If either range is VR_VARYING the other one wins.  */
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     return;
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
-      copy_value_range (vr0, vr1);
+      vr0->deep_copy (vr1);
       return;
     }
 
   /* When either range is VR_UNDEFINED the resulting range is
      VR_UNDEFINED, too.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
-  if (vr1->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
       set_value_range_to_undefined (vr0);
       return;
@@ -5848,53 +5966,56 @@ vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
 
   /* Save the original vr0 so we can return it as conservative intersection
      result when our worker turns things to varying.  */
-  saved = *vr0;
-  intersect_ranges (&vr0->type, &vr0->min, &vr0->max,
-		    vr1->type, vr1->min, vr1->max);
+  value_range saved (*vr0);
+
+  value_range_kind vr0type = vr0->kind ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  intersect_ranges (&vr0type, &vr0min, &vr0max,
+		    vr1->kind (), vr1->min (), vr1->max ());
   /* Make sure to canonicalize the result though as the inversion of a
      VR_RANGE can still be a VR_RANGE.  */
-  set_and_canonicalize_value_range (vr0, vr0->type,
-				    vr0->min, vr0->max, vr0->equiv);
+  vr0->set_and_canonicalize (vr0type, vr0min, vr0max, vr0->equiv ());
   /* If that failed, use the saved original VR0.  */
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       *vr0 = saved;
       return;
     }
   /* If the result is VR_UNDEFINED there is no need to mess with
      the equivalencies.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
 
   /* The resulting set of equivalences for range intersection is the union of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_ior_into (vr0->equiv, vr1->equiv);
-  else if (vr1->equiv && !vr0->equiv)
+  if (vr0->m_equiv && vr1->m_equiv && vr0->m_equiv != vr1->m_equiv)
+    bitmap_ior_into (vr0->m_equiv, vr1->m_equiv);
+  else if (vr1->m_equiv && !vr0->m_equiv)
     {
       /* All equivalence bitmaps are allocated from the same obstack.  So
 	 we can use the obstack associated with VR to allocate vr0->equiv.  */
-      vr0->equiv = BITMAP_ALLOC (vr1->equiv->obstack);
-      bitmap_copy (vr0->equiv, vr1->equiv);
+      vr0->m_equiv = BITMAP_ALLOC (vr1->equiv ()->obstack);
+      bitmap_copy (m_equiv, vr1->m_equiv);
     }
 }
 
 void
-vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
+value_range::intersect (const value_range *other)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Intersecting\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, vr1);
+      dump_value_range (dump_file, other);
       fprintf (dump_file, "\n");
     }
-  vrp_intersect_ranges_1 (vr0, vr1);
+  intersect_helper (this, other);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\n");
     }
 }
@@ -5903,39 +6024,41 @@ vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
    VR1, store in VR0 a range that contains both VR0 and VR1.  This
    may not be the smallest possible such range.  */
 
-static void
-vrp_meet_1 (value_range *vr0, const value_range *vr1)
+void
+value_range::union_helper (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
-  if (vr0->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
-      set_value_range (vr0, vr1->type, vr1->min, vr1->max, vr1->equiv);
+      /* VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr1->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     {
-      /* VR0 already has the resulting range.  */
+      vr0->deep_copy (vr1);
       return;
     }
 
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       /* Nothing to do.  VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     {
       set_value_range_to_varying (vr0);
       return;
     }
 
-  saved = *vr0;
-  union_ranges (&vr0->type, &vr0->min, &vr0->max,
-		vr1->type, vr1->min, vr1->max);
-  if (vr0->type == VR_VARYING)
+  value_range saved (*vr0);
+  value_range_kind vr0type = vr0->kind ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  union_ranges (&vr0type, &vr0min, &vr0max,
+		vr1->kind (), vr1->min (), vr1->max ());
+  *vr0 = value_range (vr0type, vr0min, vr0max);
+  if (vr0->varying_p ())
     {
       /* Failed to find an efficient meet.  Before giving up and setting
 	 the result to VARYING, see if we can at least derive a useful
@@ -5943,52 +6066,51 @@ vrp_meet_1 (value_range *vr0, const value_range *vr1)
       if (range_includes_zero_p (&saved) == 0
 	  && range_includes_zero_p (vr1) == 0)
 	{
-	  set_value_range_to_nonnull (vr0, TREE_TYPE (saved.min));
+	  set_value_range_to_nonnull (vr0, saved.type ());
 
 	  /* Since this meet operation did not result from the meeting of
 	     two equivalent names, VR0 cannot have any equivalences.  */
-	  if (vr0->equiv)
-	    bitmap_clear (vr0->equiv);
+	  if (vr0->m_equiv)
+	    bitmap_clear (vr0->m_equiv);
 	  return;
 	}
 
       set_value_range_to_varying (vr0);
       return;
     }
-  set_and_canonicalize_value_range (vr0, vr0->type, vr0->min, vr0->max,
-				    vr0->equiv);
-  if (vr0->type == VR_VARYING)
+  vr0->set_and_canonicalize (vr0->kind (), vr0->min (), vr0->max (),
+			     vr0->equiv ());
+  if (vr0->varying_p ())
     return;
 
   /* The resulting set of equivalences is always the intersection of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_and_into (vr0->equiv, vr1->equiv);
-  else if (vr0->equiv && !vr1->equiv)
-    bitmap_clear (vr0->equiv);
+  if (vr0->m_equiv && vr1->m_equiv && vr0->m_equiv != vr1->m_equiv)
+    bitmap_and_into (vr0->m_equiv, vr1->m_equiv);
+  else if (vr0->m_equiv && !vr1->m_equiv)
+    bitmap_clear (vr0->m_equiv);
 }
 
 void
-vrp_meet (value_range *vr0, const value_range *vr1)
+value_range::union_ (const value_range *other)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Meeting\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, vr1);
+      dump_value_range (dump_file, other);
       fprintf (dump_file, "\n");
     }
-  vrp_meet_1 (vr0, vr1);
+  union_helper (this, other);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\n");
     }
 }
 
-
 /* Visit all arguments for PHI node PHI that flow through executable
    edges.  If a valid value range can be derived from all the incoming
    value ranges, set a new range for the LHS of PHI.  */
@@ -5997,7 +6119,7 @@ enum ssa_prop_result
 vrp_prop::visit_phi (gphi *phi)
 {
   tree lhs = PHI_RESULT (phi);
-  value_range vr_result = VR_INITIALIZER;
+  value_range vr_result;
   extract_range_from_phi_node (phi, &vr_result);
   if (update_value_range (lhs, &vr_result))
     {
@@ -6010,7 +6132,7 @@ vrp_prop::visit_phi (gphi *phi)
 	  fprintf (dump_file, "\n");
 	}
 
-      if (vr_result.type == VR_VARYING)
+      if (vr_result.varying_p ())
 	return SSA_PROP_VARYING;
 
       return SSA_PROP_INTERESTING;
@@ -6194,16 +6316,17 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
       op = lhs_of_dominating_assert (op, bb, stmt);
 
       const value_range *vr = vr_values->get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  size_t i, j;
 	  /* Get the range of labels that contain a part of the operand's
 	     value range.  */
-	  find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+	  find_case_label_range (switch_stmt, vr->min (), vr->max (), &i, &j);
 
 	  /* Is there only one such label?  */
 	  if (i == j)
@@ -6213,10 +6336,11 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	      /* The i'th label will be taken only if the value range of the
 		 operand is entirely within the bounds of this label.  */
 	      if (CASE_HIGH (label) != NULL_TREE
-		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
-		     && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
-		  : (tree_int_cst_equal (CASE_LOW (label), vr->min)
-		     && tree_int_cst_equal (vr->min, vr->max)))
+		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min ()) <= 0
+		     && tree_int_cst_compare (CASE_HIGH (label),
+					      vr->max ()) >= 0)
+		  : (tree_int_cst_equal (CASE_LOW (label), vr->min ())
+		     && tree_int_cst_equal (vr->min (), vr->max ())))
 		return label;
 	    }
 
@@ -6226,7 +6350,7 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	    return gimple_switch_label (switch_stmt, 0);
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->kind () == VR_ANTI_RANGE)
 	{
 	  unsigned n = gimple_switch_num_labels (switch_stmt);
 	  tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -6235,10 +6359,12 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	  /* The default label will be taken only if the anti-range of the
 	     operand is entirely outside the bounds of all the (non-default)
 	     case labels.  */
-	  if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+	  if (tree_int_cst_compare (vr->min (), CASE_LOW (min_label)) <= 0
 	      && (CASE_HIGH (max_label) != NULL_TREE
-		  ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
-		  : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+		  ? tree_int_cst_compare (vr->max (),
+					  CASE_HIGH (max_label)) >= 0
+		  : tree_int_cst_compare (vr->max (),
+					  CASE_LOW (max_label)) >= 0))
 	  return gimple_switch_label (switch_stmt, 0);
 	}
 
@@ -6255,11 +6381,12 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	{
 	  edge dummy_e;
 	  tree dummy_tree;
-	  value_range new_vr = VR_INITIALIZER;
+	  value_range new_vr;
 	  vr_values->extract_range_from_stmt (stmt, &dummy_e,
 					      &dummy_tree, &new_vr);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  tree singleton;
+	  if ((singleton = new_vr.singleton_p ()))
+	    return singleton;
 	}
     }
 
@@ -6431,20 +6558,16 @@ vrp_prop::vrp_finalize (bool warn_array_bounds_p)
 	continue;
 
       const value_range *vr = get_value_range (name);
-      if (!name
-	  || (vr->type == VR_VARYING)
-	  || (vr->type == VR_UNDEFINED)
-	  || (TREE_CODE (vr->min) != INTEGER_CST)
-	  || (TREE_CODE (vr->max) != INTEGER_CST))
+      if (!name || !vr->constant_p ())
 	continue;
 
       if (POINTER_TYPE_P (TREE_TYPE (name))
 	  && range_includes_zero_p (vr) == 0)
 	set_ptr_nonnull (name);
       else if (!POINTER_TYPE_P (TREE_TYPE (name)))
-	set_range_info (name, vr->type,
-			wi::to_wide (vr->min),
-			wi::to_wide (vr->max));
+	set_range_info (name, vr->kind (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
     }
 
   /* If we're checking array refs, we want to merge information on
@@ -6636,7 +6759,7 @@ determine_value_range_1 (value_range *vr, tree expr)
 {
   if (BINARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER, vr1 = VR_INITIALIZER;
+      value_range vr0, vr1;
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       determine_value_range_1 (&vr1, TREE_OPERAND (expr, 1));
       extract_range_from_binary_expr_1 (vr, TREE_CODE (expr), TREE_TYPE (expr),
@@ -6644,7 +6767,7 @@ determine_value_range_1 (value_range *vr, tree expr)
     }
   else if (UNARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER;
+      value_range vr0;
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       extract_range_from_unary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr),
 				     &vr0, TREE_TYPE (TREE_OPERAND (expr, 0)));
@@ -6653,7 +6776,7 @@ determine_value_range_1 (value_range *vr, tree expr)
     set_value_range_to_value (vr, expr, NULL);
   else
     {
-      value_range_type kind;
+      value_range_kind kind;
       wide_int min, max;
       /* For SSA names try to extract range info computed by VRP.  Otherwise
 	 fall back to varying.  */
@@ -6670,18 +6793,16 @@ determine_value_range_1 (value_range *vr, tree expr)
 /* Compute a value-range for EXPR and set it in *MIN and *MAX.  Return
    the determined range type.  */
 
-value_range_type
+value_range_kind
 determine_value_range (tree expr, wide_int *min, wide_int *max)
 {
-  value_range vr = VR_INITIALIZER;
+  value_range vr;
   determine_value_range_1 (&vr, expr);
-  if ((vr.type == VR_RANGE
-       || vr.type == VR_ANTI_RANGE)
-      && !symbolic_range_p (&vr))
+  if (vr.constant_p ())
     {
-      *min = wi::to_wide (vr.min);
-      *max = wi::to_wide (vr.max);
-      return vr.type;
+      *min = wi::to_wide (vr.min ());
+      *max = wi::to_wide (vr.max ());
+      return vr.kind ();
     }
 
   return VR_VARYING;
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index 655cf055f0a..8103fd4f31a 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -20,42 +20,147 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_TREE_VRP_H
 #define GCC_TREE_VRP_H
 
-/* Type of value ranges.  See value_range below for a
-   description of these types.  */
-enum value_range_type { VR_UNDEFINED, VR_RANGE,
-			VR_ANTI_RANGE, VR_VARYING, VR_LAST };
+/* Types of value ranges.  */
+enum value_range_kind
+{
+ /* Empty range.  */
+ VR_UNDEFINED,
+ /* Range spans the entire domain.  */
+ VR_VARYING,
+ /* Range is [MIN, MAX].  */
+ VR_RANGE,
+ /* Range is ~[MIN, MAX].  */
+ VR_ANTI_RANGE,
+ /* Range is a nice guy.  */
+ VR_LAST
+};
 
 /* Range of values that can be associated with an SSA_NAME after VRP
    has executed.  */
-struct GTY((for_user)) value_range
+class GTY((for_user)) value_range
 {
-  /* Lattice value represented by this range.  */
-  enum value_range_type type;
+ public:
+  value_range ();
+  value_range (value_range_kind, tree, tree, bitmap = NULL);
+  bool operator== (const value_range &) const;
+  bool operator!= (const value_range &) const;
+  void intersect (const value_range *);
+  void union_ (const value_range *);
+
+  /* Types of value ranges.  */
+  bool undefined_p () const;
+  bool varying_p () const;
+  bool symbolic_p () const;
+  bool constant_p () const;
+  void set_undefined ();
+  void set_varying ();
+
+  /* Equivalence bitmap methods.  */
+  bitmap equiv () const;
+  void set_equiv (bitmap);
+  void equiv_clear ();
+
+  /* Misc methods.  */
+  tree type () const;
+  bool null_p () const;
+  bool may_contain_p (tree) const;
+  tree singleton_p () const;
+  void deep_copy (const value_range *);
+  bool ignore_equivs_equal_p (const value_range &) const;
+  void set_and_canonicalize (enum value_range_kind, tree, tree, bitmap);
+  void dump () const;
 
-  /* Minimum and maximum values represented by this range.  These
-     values should be interpreted as follows:
+  enum value_range_kind kind () const;
+  tree min () const;
+  tree max () const;
+
+ private:
+  void set (value_range_kind, tree, tree, bitmap);
+  void check ();
+  bool equal_p (const value_range &, bool ignore_equivs) const;
+  void intersect_helper (value_range *, const value_range *);
+  void union_helper (value_range *, const value_range *);
+
+  enum value_range_kind m_kind;
+ public:
+  /* These should be private, but GTY is a piece of crap.  */
+  tree m_min;
+  tree m_max;
+  /* Set of SSA names whose value ranges are equivalent to this one.
+     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
+  bitmap m_equiv;
+};
 
-	- If TYPE is VR_UNDEFINED or VR_VARYING then MIN and MAX must
-	  be NULL.
+inline
+value_range::value_range ()
+{
+  m_kind = VR_UNDEFINED;
+  m_min = m_max = NULL;
+  m_equiv = NULL;
+}
 
-	- If TYPE == VR_RANGE then MIN holds the minimum value and
-	  MAX holds the maximum value of the range [MIN, MAX].
+/* Return the kind of this range.  */
 
-	- If TYPE == ANTI_RANGE the variable is known to NOT
-	  take any values in the range [MIN, MAX].  */
-  tree min;
-  tree max;
+inline value_range_kind
+value_range::kind () const
+{
+  return m_kind;
+}
 
-  /* Set of SSA names whose value ranges are equivalent to this one.
-     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
-  bitmap equiv;
+inline bitmap
+value_range::equiv () const
+{
+  return m_equiv;
+}
 
-  /* Dump value range to stderr.  */
-  void dump () const;
-};
+/* Return the lower bound.  */
+
+inline tree
+value_range::min () const
+{
+  return m_min;
+}
+
+/* Return the upper bound.  */
+
+inline tree
+value_range::max () const
+{
+  return m_max;
+}
+
+/* Return TRUE if range spans the entire possible domain.  */
+
+inline bool
+value_range::varying_p () const
+{
+  return m_kind == VR_VARYING;
+}
+
+/* Return TRUE if range is undefined (essentially the empty set).  */
+
+inline bool
+value_range::undefined_p () const
+{
+  return m_kind == VR_UNDEFINED;
+}
+
+inline void
+value_range::set_equiv (bitmap b)
+{
+  m_equiv = b;
+}
+
+/* Return TRUE if range is the constant zero.  */
+
+inline bool
+value_range::null_p () const
+{
+  return (m_kind == VR_RANGE
+	  && integer_zerop (m_min)
+	  && integer_zerop (m_max));
+}
 
-extern void vrp_intersect_ranges (value_range *vr0, const value_range *vr1);
-extern void vrp_meet (value_range *vr0, const value_range *vr1);
 extern void dump_value_range (FILE *, const value_range *);
 extern void extract_range_from_unary_expr (value_range *vr,
 					   enum tree_code code,
@@ -64,8 +169,8 @@ extern void extract_range_from_unary_expr (value_range *vr,
 					   tree op0_type);
 
 extern bool vrp_operand_equal_p (const_tree, const_tree);
-extern enum value_range_type intersect_range_with_nonzero_bits
-  (enum value_range_type, wide_int *, wide_int *, const wide_int &, signop);
+extern enum value_range_kind intersect_range_with_nonzero_bits
+  (enum value_range_kind, wide_int *, wide_int *, const wide_int &, signop);
 
 struct assert_info
 {
@@ -90,19 +195,14 @@ extern bool range_includes_zero_p (const value_range *);
 extern bool infer_value_range (gimple *, tree, tree_code *, tree *);
 
 extern void set_value_range_to_nonnull (value_range *, tree);
-extern void set_value_range (value_range *, enum value_range_type, tree,
+extern void set_value_range (value_range *, enum value_range_kind, tree,
 			     tree, bitmap);
-extern void set_and_canonicalize_value_range (value_range *,
-					      enum value_range_type,
-					      tree, tree, bitmap);
 extern bool vrp_bitmap_equal_p (const_bitmap, const_bitmap);
 extern tree value_range_constant_singleton (const value_range *);
-extern bool symbolic_range_p (const value_range *);
 extern int compare_values (tree, tree);
 extern int compare_values_warnv (tree, tree, bool *);
 extern bool vrp_val_is_min (const_tree);
 extern bool vrp_val_is_max (const_tree);
-extern void copy_value_range (value_range *, const value_range *);
 extern void set_value_range_to_value (value_range *, tree, bitmap);
 extern void extract_range_from_binary_expr_1 (value_range *, enum tree_code,
 					      tree, const value_range *,
@@ -121,5 +221,5 @@ extern bool range_int_cst_singleton_p (const value_range *);
 extern int value_inside_range (tree, tree, tree);
 extern tree get_single_symbol (tree, bool *, tree *);
 extern void maybe_set_nonzero_bits (edge, tree);
-extern value_range_type determine_value_range (tree, wide_int *, wide_int *);
+extern value_range_kind determine_value_range (tree, wide_int *, wide_int *);
 #endif /* GCC_TREE_VRP_H */
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 32392a11618..28921431009 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -55,7 +55,7 @@ static inline void
 set_value_range_to_nonnegative (value_range *vr, tree type)
 {
   tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_RANGE, zero, vrp_val_max (type), vr->equiv);
+  set_value_range (vr, VR_RANGE, zero, vrp_val_max (type), vr->equiv ());
 }
 
 /* Set value range VR to a range of a truthvalue of type TYPE.  */
@@ -68,7 +68,7 @@ set_value_range_to_truthvalue (value_range *vr, tree type)
   else
     set_value_range (vr, VR_RANGE,
 		     build_int_cst (type, 0), build_int_cst (type, 1),
-		     vr->equiv);
+		     vr->equiv ());
 }
 
 
@@ -80,8 +80,7 @@ set_value_range_to_truthvalue (value_range *vr, tree type)
 value_range *
 vr_values::get_value_range (const_tree var)
 {
-  static const value_range vr_const_varying
-    = { VR_VARYING, NULL_TREE, NULL_TREE, NULL };
+  static const value_range vr_const_varying (VR_VARYING, NULL, NULL);
   value_range *vr;
   tree sym;
   unsigned ver = SSA_NAME_VERSION (var);
@@ -106,10 +105,7 @@ vr_values::get_value_range (const_tree var)
 
   /* Create a default value range.  */
   vr_value[ver] = vr = vrp_value_range_pool.allocate ();
-  memset (vr, 0, sizeof (*vr));
-
-  /* Defer allocating the equivalence set.  */
-  vr->equiv = NULL;
+  vr->set_undefined ();
 
   /* If VAR is a default definition of a parameter, the variable can
      take any value in VAR's type.  */
@@ -128,7 +124,7 @@ vr_values::get_value_range (const_tree var)
 	  else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
 	    {
 	      wide_int min, max;
-	      value_range_type rtype = get_range_info (var, &min, &max);
+	      value_range_kind rtype = get_range_info (var, &min, &max);
 	      if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
 		set_value_range (vr, rtype,
 				 wide_int_to_tree (TREE_TYPE (var), min),
@@ -159,7 +155,7 @@ vr_values::set_defs_to_varying (gimple *stmt)
     {
       value_range *vr = get_value_range (def);
       /* Avoid writing to vr_const_varying get_value_range may return.  */
-      if (vr->type != VR_VARYING)
+      if (!vr->varying_p ())
 	set_value_range_to_varying (vr);
     }
 }
@@ -185,24 +181,21 @@ vr_values::update_value_range (const_tree var, value_range *new_vr)
   if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
     {
       wide_int min, max;
-      value_range_type rtype = get_range_info (var, &min, &max);
+      value_range_kind rtype = get_range_info (var, &min, &max);
       if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
 	{
 	  tree nr_min, nr_max;
 	  nr_min = wide_int_to_tree (TREE_TYPE (var), min);
 	  nr_max = wide_int_to_tree (TREE_TYPE (var), max);
-	  value_range nr = VR_INITIALIZER;
-	  set_and_canonicalize_value_range (&nr, rtype, nr_min, nr_max, NULL);
-	  vrp_intersect_ranges (new_vr, &nr);
+	  value_range nr;
+	  nr.set_and_canonicalize (rtype, nr_min, nr_max, NULL);
+	  new_vr->intersect (&nr);
 	}
     }
 
   /* Update the value range, if necessary.  */
   old_vr = get_value_range (var);
-  is_new = old_vr->type != new_vr->type
-	   || !vrp_operand_equal_p (old_vr->min, new_vr->min)
-	   || !vrp_operand_equal_p (old_vr->max, new_vr->max)
-	   || !vrp_bitmap_equal_p (old_vr->equiv, new_vr->equiv);
+  is_new = *old_vr != *new_vr;
 
   if (is_new)
     {
@@ -212,19 +205,18 @@ vr_values::update_value_range (const_tree var, value_range *new_vr)
 	 the same.  We may not have is_new when transitioning to
 	 UNDEFINED.  If old_vr->type is VARYING, we shouldn't be
 	 called.  */
-      if (new_vr->type == VR_UNDEFINED)
+      if (new_vr->undefined_p ())
 	{
-	  BITMAP_FREE (new_vr->equiv);
 	  set_value_range_to_varying (old_vr);
 	  set_value_range_to_varying (new_vr);
 	  return true;
 	}
       else
-	set_value_range (old_vr, new_vr->type, new_vr->min, new_vr->max,
-			 new_vr->equiv);
+	set_value_range (old_vr, new_vr->kind (),
+			 new_vr->min (), new_vr->max (), new_vr->equiv ());
     }
 
-  BITMAP_FREE (new_vr->equiv);
+  new_vr->equiv_clear ();
 
   return is_new;
 }
@@ -233,17 +225,19 @@ vr_values::update_value_range (const_tree var, value_range *new_vr)
 /* Add VAR and VAR's equivalence set to EQUIV.  This is the central
    point where equivalence processing can be turned on/off.  */
 
-void
-vr_values::add_equivalence (bitmap *equiv, const_tree var)
+bitmap
+vr_values::add_equivalence (bitmap equiv, const_tree var)
 {
   unsigned ver = SSA_NAME_VERSION (var);
   value_range *vr = get_value_range (var);
+  bitmap ret = equiv;
 
-  if (*equiv == NULL)
-    *equiv = BITMAP_ALLOC (&vrp_equiv_obstack);
-  bitmap_set_bit (*equiv, ver);
-  if (vr && vr->equiv)
-    bitmap_ior_into (*equiv, vr->equiv);
+  if (ret == NULL)
+    ret = BITMAP_ALLOC (&vrp_equiv_obstack);
+  bitmap_set_bit (ret, ver);
+  if (vr && vr->equiv ())
+    bitmap_ior_into (ret, vr->equiv ());
+  return ret;
 }
 
 /* Return true if value range VR involves exactly one symbol SYM.  */
@@ -254,16 +248,16 @@ symbolic_range_based_on_p (value_range *vr, const_tree sym)
   bool neg, min_has_symbol, max_has_symbol;
   tree inv;
 
-  if (is_gimple_min_invariant (vr->min))
+  if (is_gimple_min_invariant (vr->min ()))
     min_has_symbol = false;
-  else if (get_single_symbol (vr->min, &neg, &inv) == sym)
+  else if (get_single_symbol (vr->min (), &neg, &inv) == sym)
     min_has_symbol = true;
   else
     return false;
 
-  if (is_gimple_min_invariant (vr->max))
+  if (is_gimple_min_invariant (vr->max ()))
     max_has_symbol = false;
-  else if (get_single_symbol (vr->max, &neg, &inv) == sym)
+  else if (get_single_symbol (vr->max (), &neg, &inv) == sym)
     max_has_symbol = true;
   else
     return false;
@@ -403,9 +397,9 @@ vr_values::op_with_boolean_value_range_p (tree op)
     return false;
 
   vr = get_value_range (op);
-  return (vr->type == VR_RANGE
-	  && integer_zerop (vr->min)
-	  && integer_onep (vr->max));
+  return (vr->kind () == VR_RANGE
+	  && integer_zerop (vr->min ())
+	  && integer_onep (vr->max ()));
 }
 
 /* Extract value range information for VAR when (OP COND_CODE LIMIT) is
@@ -438,12 +432,13 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 
   /* LIMIT's range is only interesting if it has any useful information.  */
   if (! limit_vr
-      || limit_vr->type == VR_UNDEFINED
-      || limit_vr->type == VR_VARYING
-      || (symbolic_range_p (limit_vr)
-	  && ! (limit_vr->type == VR_RANGE
-		&& (limit_vr->min == limit_vr->max
-		    || operand_equal_p (limit_vr->min, limit_vr->max, 0)))))
+      || limit_vr->undefined_p ()
+      || limit_vr->varying_p ()
+      || (limit_vr->symbolic_p ()
+	  && ! (limit_vr->kind () == VR_RANGE
+		&& (limit_vr->min () == limit_vr->max ()
+		    || operand_equal_p (limit_vr->min (),
+					limit_vr->max (), 0)))))
     limit_vr = NULL;
 
   /* Initially, the new range has the same set of equivalences of
@@ -451,8 +446,8 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
      value.  Since assertions may be chained via mutually exclusive
      predicates, we will need to trim the set of equivalences before
      we are done.  */
-  gcc_assert (vr_p->equiv == NULL);
-  add_equivalence (&vr_p->equiv, var);
+  gcc_assert (vr_p->equiv () == NULL);
+  vr_p->set_equiv (add_equivalence (NULL, var));
 
   /* Extract a new range based on the asserted comparison for VAR and
      LIMIT's value range.  Notice that if LIMIT has an anti-range, we
@@ -488,26 +483,24 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
       max = force_fit_type (TREE_TYPE (var), wi::to_widest (max), 0, false);
 
       /* We can transform a max, min range to an anti-range or
-         vice-versa.  Use set_and_canonicalize_value_range which does
-	 this for us.  */
+         vice-versa.  Use set_and_canonicalize which does this for
+         us.  */
       if (cond_code == LE_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_RANGE,
-					  min, max, vr_p->equiv);
+        vr_p->set_and_canonicalize (VR_RANGE, min, max, vr_p->equiv ());
       else if (cond_code == GT_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					  min, max, vr_p->equiv);
+        vr_p->set_and_canonicalize (VR_ANTI_RANGE, min, max, vr_p->equiv ());
       else
 	gcc_unreachable ();
     }
   else if (cond_code == EQ_EXPR)
     {
-      enum value_range_type range_type;
+      enum value_range_kind range_type;
 
       if (limit_vr)
 	{
-	  range_type = limit_vr->type;
-	  min = limit_vr->min;
-	  max = limit_vr->max;
+	  range_type = limit_vr->kind ();
+	  min = limit_vr->min ();
+	  max = limit_vr->max ();
 	}
       else
 	{
@@ -516,13 +509,13 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	  max = limit;
 	}
 
-      set_value_range (vr_p, range_type, min, max, vr_p->equiv);
+      set_value_range (vr_p, range_type, min, max, vr_p->equiv ());
 
       /* When asserting the equality VAR == LIMIT and LIMIT is another
 	 SSA name, the new range will also inherit the equivalence set
 	 from LIMIT.  */
       if (TREE_CODE (limit) == SSA_NAME)
-	add_equivalence (&vr_p->equiv, limit);
+	vr_p->set_equiv (add_equivalence (vr_p->equiv (), limit));
     }
   else if (cond_code == NE_EXPR)
     {
@@ -547,11 +540,11 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	 (i.e., LIMIT_VR->MIN == LIMIT_VR->MAX).  In that case,
 	 build the anti-range ~[LIMIT_VR->MIN, LIMIT_VR->MAX].  */
       if (limit_vr
-	  && limit_vr->type == VR_RANGE
-	  && compare_values (limit_vr->min, limit_vr->max) == 0)
+	  && limit_vr->kind () == VR_RANGE
+	  && compare_values (limit_vr->min (), limit_vr->max ()) == 0)
 	{
-	  min = limit_vr->min;
-	  max = limit_vr->max;
+	  min = limit_vr->min ();
+	  max = limit_vr->max ();
 	}
       else
 	{
@@ -567,21 +560,20 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	  && vrp_val_is_max (max))
 	min = max = limit;
 
-      set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					min, max, vr_p->equiv);
+      vr_p->set_and_canonicalize (VR_ANTI_RANGE, min, max, vr_p->equiv ());
     }
   else if (cond_code == LE_EXPR || cond_code == LT_EXPR)
     {
       min = TYPE_MIN_VALUE (type);
 
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+      if (limit_vr == NULL || limit_vr->kind () == VR_ANTI_RANGE)
 	max = limit;
       else
 	{
 	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
 	     range [MIN, N2] for LE_EXPR and [MIN, N2 - 1] for
 	     LT_EXPR.  */
-	  max = limit_vr->max;
+	  max = limit_vr->max ();
 	}
 
       /* If the maximum value forces us to be out of bounds, simply punt.
@@ -607,21 +599,21 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 		TREE_NO_WARNING (max) = 1;
 	    }
 
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv ());
 	}
     }
   else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
     {
       max = TYPE_MAX_VALUE (type);
 
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+      if (limit_vr == NULL || limit_vr->kind () == VR_ANTI_RANGE)
 	min = limit;
       else
 	{
 	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
 	     range [N1, MAX] for GE_EXPR and [N1 + 1, MAX] for
 	     GT_EXPR.  */
-	  min = limit_vr->min;
+	  min = limit_vr->min ();
 	}
 
       /* If the minimum value forces us to be out of bounds, simply punt.
@@ -647,14 +639,14 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 		TREE_NO_WARNING (min) = 1;
 	    }
 
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv ());
 	}
     }
   else
     gcc_unreachable ();
 
   /* Finally intersect the new range with what we already know about var.  */
-  vrp_intersect_ranges (vr_p, get_value_range (var));
+  vr_p->intersect (get_value_range (var));
 }
 
 /* Extract value range information from an ASSERT_EXPR EXPR and store
@@ -711,12 +703,12 @@ vr_values::extract_range_from_ssa_name (value_range *vr, tree var)
 {
   value_range *var_vr = get_value_range (var);
 
-  if (var_vr->type != VR_VARYING)
-    copy_value_range (vr, var_vr);
+  if (!var_vr->varying_p ())
+    vr->deep_copy (var_vr);
   else
     set_value_range (vr, VR_RANGE, var, var, NULL);
 
-  add_equivalence (&vr->equiv, var);
+  vr->set_equiv (add_equivalence (vr->equiv (), var));
 }
 
 /* Extract range information from a binary expression OP0 CODE OP1 based on
@@ -728,11 +720,9 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
 					   enum tree_code code,
 					   tree expr_type, tree op0, tree op1)
 {
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
+  value_range vr0, vr1;
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
   else if (is_gimple_min_invariant (op0))
@@ -752,18 +742,14 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
   if (INTEGRAL_TYPE_P (TREE_TYPE (op0))
       && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)))
     {
-      if (vr0.type == VR_VARYING && vr1.type != VR_VARYING)
-	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = vrp_val_min (expr_type);
-	  vr0.max = vrp_val_max (expr_type);
-	}
-      else if (vr1.type == VR_VARYING && vr0.type != VR_VARYING)
-	{
-	  vr1.type = VR_RANGE;
-	  vr1.min = vrp_val_min (expr_type);
-	  vr1.max = vrp_val_max (expr_type);
-	}
+      if (vr0.varying_p () && !vr1.varying_p ())
+	vr0 = value_range (VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type));
+      else if (vr1.varying_p () && !vr0.varying_p ())
+	vr1 = value_range (VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type));
     }
 
   extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
@@ -773,7 +759,7 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
      n = def - arg
      Here the range for n can be set to [0, PTRDIFF_MAX - 1]. */
 
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && code == POINTER_DIFF_EXPR
       && TREE_CODE (op0) == SSA_NAME
       && TREE_CODE (op1) == SSA_NAME)
@@ -806,21 +792,21 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
      symbolic comparison.  When a bound of the range of the first operand
      is invariant, we set the corresponding bound of the new range to INF
      in order to avoid recursing on the range of the second operand.  */
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == PLUS_EXPR || code == MINUS_EXPR)
       && TREE_CODE (op1) == SSA_NAME
-      && vr0.type == VR_RANGE
+      && vr0.kind () == VR_RANGE
       && symbolic_range_based_on_p (&vr0, op1))
     {
       const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr1 = VR_INITIALIZER;
+      value_range n_vr1;
 
       /* Try with VR0 and [-INF, OP1].  */
-      if (is_gimple_min_invariant (minus_p ? vr0.max : vr0.min))
+      if (is_gimple_min_invariant (minus_p ? vr0.max () : vr0.min ()))
 	set_value_range (&n_vr1, VR_RANGE, vrp_val_min (expr_type), op1, NULL);
 
       /* Try with VR0 and [OP1, +INF].  */
-      else if (is_gimple_min_invariant (minus_p ? vr0.min : vr0.max))
+      else if (is_gimple_min_invariant (minus_p ? vr0.min () : vr0.max ()))
 	set_value_range (&n_vr1, VR_RANGE, op1, vrp_val_max (expr_type), NULL);
 
       /* Try with VR0 and [OP1, OP1].  */
@@ -830,21 +816,21 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
       extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1);
     }
 
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == PLUS_EXPR || code == MINUS_EXPR)
       && TREE_CODE (op0) == SSA_NAME
-      && vr1.type == VR_RANGE
+      && vr1.kind () == VR_RANGE
       && symbolic_range_based_on_p (&vr1, op0))
     {
       const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr0 = VR_INITIALIZER;
+      value_range n_vr0;
 
       /* Try with [-INF, OP0] and VR1.  */
-      if (is_gimple_min_invariant (minus_p ? vr1.max : vr1.min))
+      if (is_gimple_min_invariant (minus_p ? vr1.max () : vr1.min ()))
 	set_value_range (&n_vr0, VR_RANGE, vrp_val_min (expr_type), op0, NULL);
 
       /* Try with [OP0, +INF] and VR1.  */
-      else if (is_gimple_min_invariant (minus_p ? vr1.min : vr1.max))
+      else if (is_gimple_min_invariant (minus_p ? vr1.min (): vr1.max ()))
 	set_value_range (&n_vr0, VR_RANGE, op0, vrp_val_max (expr_type), NULL);
 
       /* Try with [OP0, OP0] and VR1.  */
@@ -858,15 +844,15 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
      op1's range is ~[op0,op0] or vice-versa, then we
      can derive a non-null range.  This happens often for
      pointer subtraction.  */
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == MINUS_EXPR || code == POINTER_DIFF_EXPR)
       && TREE_CODE (op0) == SSA_NAME
-      && ((vr0.type == VR_ANTI_RANGE
-	   && vr0.min == op1
-	   && vr0.min == vr0.max)
-	  || (vr1.type == VR_ANTI_RANGE
-	      && vr1.min == op0
-	      && vr1.min == vr1.max)))
+      && ((vr0.kind () == VR_ANTI_RANGE
+	   && vr0.min () == op1
+	   && vr0.min () == vr0.max ())
+	  || (vr1.kind () == VR_ANTI_RANGE
+	      && vr1.min () == op0
+	      && vr1.min () == vr1.max ())))
       set_value_range_to_nonnull (vr, expr_type);
 }
 
@@ -878,7 +864,7 @@ void
 vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code,
 					  tree type, tree op0)
 {
-  value_range vr0 = VR_INITIALIZER;
+  value_range vr0;
 
   /* Get value ranges for the operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
@@ -899,13 +885,10 @@ vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code,
 void
 vr_values::extract_range_from_cond_expr (value_range *vr, gassign *stmt)
 {
-  tree op0, op1;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
-  op0 = gimple_assign_rhs2 (stmt);
+  tree op0 = gimple_assign_rhs2 (stmt);
+  value_range vr0;
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
   else if (is_gimple_min_invariant (op0))
@@ -913,7 +896,8 @@ vr_values::extract_range_from_cond_expr (value_range *vr, gassign *stmt)
   else
     set_value_range_to_varying (&vr0);
 
-  op1 = gimple_assign_rhs3 (stmt);
+  tree op1 = gimple_assign_rhs3 (stmt);
+  value_range vr1;
   if (TREE_CODE (op1) == SSA_NAME)
     vr1 = *(get_value_range (op1));
   else if (is_gimple_min_invariant (op1))
@@ -922,8 +906,8 @@ vr_values::extract_range_from_cond_expr (value_range *vr, gassign *stmt)
     set_value_range_to_varying (&vr1);
 
   /* The resulting value range is the union of the operand ranges */
-  copy_value_range (vr, &vr0);
-  vrp_meet (vr, &vr1);
+  vr->deep_copy (&vr0);
+  vr->union_ (&vr1);
 }
 
 
@@ -946,9 +930,9 @@ vr_values::extract_range_from_comparison (value_range *vr, enum tree_code code,
 	 type.  */
       val = fold_convert (type, val);
       if (is_gimple_min_invariant (val))
-	set_value_range_to_value (vr, val, vr->equiv);
+	set_value_range_to_value (vr, val, vr->equiv ());
       else
-	set_value_range (vr, VR_RANGE, val, val, vr->equiv);
+	set_value_range (vr, VR_RANGE, val, val, vr->equiv ());
     }
   else
     /* The result of a comparison is always true or false.  */
@@ -965,8 +949,7 @@ bool
 vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
 					 tree op0, tree op1, bool *ovf)
 {
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
+  value_range vr0, vr1;
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *get_value_range (op0);
   else if (TREE_CODE (op0) == INTEGER_CST)
@@ -981,29 +964,31 @@ vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
   else
     set_value_range_to_varying (&vr1);
 
+  tree vr0min = vr0.min (), vr0max = vr0.max ();
+  tree vr1min = vr1.min (), vr1max = vr1.max ();
   if (!range_int_cst_p (&vr0)
-      || TREE_OVERFLOW (vr0.min)
-      || TREE_OVERFLOW (vr0.max))
+      || TREE_OVERFLOW (vr0min)
+      || TREE_OVERFLOW (vr0max))
     {
-      vr0.min = vrp_val_min (TREE_TYPE (op0));
-      vr0.max = vrp_val_max (TREE_TYPE (op0));
+      vr0min = vrp_val_min (TREE_TYPE (op0));
+      vr0max = vrp_val_max (TREE_TYPE (op0));
     }
   if (!range_int_cst_p (&vr1)
-      || TREE_OVERFLOW (vr1.min)
-      || TREE_OVERFLOW (vr1.max))
+      || TREE_OVERFLOW (vr1min)
+      || TREE_OVERFLOW (vr1max))
     {
-      vr1.min = vrp_val_min (TREE_TYPE (op1));
-      vr1.max = vrp_val_max (TREE_TYPE (op1));
+      vr1min = vrp_val_min (TREE_TYPE (op1));
+      vr1max = vrp_val_max (TREE_TYPE (op1));
     }
-  *ovf = arith_overflowed_p (subcode, type, vr0.min,
-			     subcode == MINUS_EXPR ? vr1.max : vr1.min);
-  if (arith_overflowed_p (subcode, type, vr0.max,
-			  subcode == MINUS_EXPR ? vr1.min : vr1.max) != *ovf)
+  *ovf = arith_overflowed_p (subcode, type, vr0min,
+			     subcode == MINUS_EXPR ? vr1max : vr1min);
+  if (arith_overflowed_p (subcode, type, vr0max,
+			  subcode == MINUS_EXPR ? vr1min : vr1max) != *ovf)
     return false;
   if (subcode == MULT_EXPR)
     {
-      if (arith_overflowed_p (subcode, type, vr0.min, vr1.max) != *ovf
-	  || arith_overflowed_p (subcode, type, vr0.max, vr1.min) != *ovf)
+      if (arith_overflowed_p (subcode, type, vr0min, vr1max) != *ovf
+	  || arith_overflowed_p (subcode, type, vr0max, vr1min) != *ovf)
 	return false;
     }
   if (*ovf)
@@ -1016,10 +1001,10 @@ vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
       widest_int wmin, wmax;
       widest_int w[4];
       int i;
-      w[0] = wi::to_widest (vr0.min);
-      w[1] = wi::to_widest (vr0.max);
-      w[2] = wi::to_widest (vr1.min);
-      w[3] = wi::to_widest (vr1.max);
+      w[0] = wi::to_widest (vr0min);
+      w[1] = wi::to_widest (vr0max);
+      w[2] = wi::to_widest (vr1min);
+      w[3] = wi::to_widest (vr1max);
       for (i = 0; i < 4; i++)
 	{
 	  widest_int wt;
@@ -1113,11 +1098,11 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		mini = 1;
 	      /* If some high bits are known to be zero,
 		 we can decrease the maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST
-		  && !operand_less_p (vr0->min,
-				      build_zero_cst (TREE_TYPE (vr0->min))))
-		maxi = tree_floor_log2 (vr0->max) + 1;
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST
+		  && !operand_less_p (vr0->min (),
+				      build_zero_cst (TREE_TYPE (vr0->min ()))))
+		maxi = tree_floor_log2 (vr0->max ()) + 1;
 	    }
 	  goto bitop_builtin;
 	  /* __builtin_parity* returns [0, 1].  */
@@ -1148,15 +1133,15 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	      value_range *vr0 = get_value_range (arg);
 	      /* From clz of VR_RANGE minimum we can compute
 		 result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->min) == INTEGER_CST)
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->min ()) == INTEGER_CST)
 		{
-		  maxi = prec - 1 - tree_floor_log2 (vr0->min);
+		  maxi = prec - 1 - tree_floor_log2 (vr0->min ());
 		  if (maxi != prec)
 		    mini = 0;
 		}
-	      else if (vr0->type == VR_ANTI_RANGE
-		       && integer_zerop (vr0->min))
+	      else if (vr0->kind () == VR_ANTI_RANGE
+		       && integer_zerop (vr0->min ()))
 		{
 		  maxi = prec - 1;
 		  mini = 0;
@@ -1165,10 +1150,10 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		break;
 	      /* From clz of VR_RANGE maximum we can compute
 		 result minimum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST)
 		{
-		  mini = prec - 1 - tree_floor_log2 (vr0->max);
+		  mini = prec - 1 - tree_floor_log2 (vr0->max ());
 		  if (mini == prec)
 		    break;
 		}
@@ -1204,20 +1189,20 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	    {
 	      value_range *vr0 = get_value_range (arg);
 	      /* If arg is non-zero, then use [0, prec - 1].  */
-	      if ((vr0->type == VR_RANGE
-		   && integer_nonzerop (vr0->min))
-		  || (vr0->type == VR_ANTI_RANGE
-		      && integer_zerop (vr0->min)))
+	      if ((vr0->kind () == VR_RANGE
+		   && integer_nonzerop (vr0->min ()))
+		  || (vr0->kind () == VR_ANTI_RANGE
+		      && integer_zerop (vr0->min ())))
 		{
 		  mini = 0;
 		  maxi = prec - 1;
 		}
 	      /* If some high bits are known to be zero,
 		 we can decrease the result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST)
 		{
-		  maxi = tree_floor_log2 (vr0->max);
+		  maxi = tree_floor_log2 (vr0->max ());
 		  /* For vr0 [0, 0] give up.  */
 		  if (maxi == -1)
 		    break;
@@ -1302,9 +1287,9 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	     this should have been already folded and if not, it
 	     wasn't folded because of overflow.  Avoid removing the
 	     UBSAN_CHECK_* calls in that case.  */
-	  if (vr->type == VR_RANGE
-	      && (vr->min == vr->max
-		  || operand_equal_p (vr->min, vr->max, 0)))
+	  if (vr->kind () == VR_RANGE
+	      && (vr->min () == vr->max ()
+		  || operand_equal_p (vr->min (), vr->max (), 0)))
 	    set_value_range_to_varying (vr);
 	  return;
 	}
@@ -1381,8 +1366,7 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		    }
 		  else
 		    {
-		      value_range vr0 = VR_INITIALIZER;
-		      value_range vr1 = VR_INITIALIZER;
+		      value_range vr0, vr1;
 		      bool saved_flag_wrapv = flag_wrapv;
 		      /* Pretend the arithmetics is wrapping.  If there is
 			 any overflow, IMAGPART_EXPR will be set.  */
@@ -1444,7 +1428,7 @@ vr_values::extract_range_from_assignment (value_range *vr, gassign *stmt)
   else
     set_value_range_to_varying (vr);
 
-  if (vr->type == VR_VARYING)
+  if (vr->varying_p ())
     extract_range_basic (vr, stmt);
 }
 
@@ -1467,18 +1451,18 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 		bool *strict_overflow_p)
 {
   /* VARYING or UNDEFINED ranges cannot be compared.  */
-  if (vr0->type == VR_VARYING
-      || vr0->type == VR_UNDEFINED
-      || vr1->type == VR_VARYING
-      || vr1->type == VR_UNDEFINED)
+  if (vr0->varying_p ()
+      || vr0->undefined_p ()
+      || vr1->varying_p ()
+      || vr1->undefined_p ())
     return NULL_TREE;
 
   /* Anti-ranges need to be handled separately.  */
-  if (vr0->type == VR_ANTI_RANGE || vr1->type == VR_ANTI_RANGE)
+  if (vr0->kind () == VR_ANTI_RANGE || vr1->kind () == VR_ANTI_RANGE)
     {
       /* If both are anti-ranges, then we cannot compute any
 	 comparison.  */
-      if (vr0->type == VR_ANTI_RANGE && vr1->type == VR_ANTI_RANGE)
+      if (vr0->kind () == VR_ANTI_RANGE && vr1->kind () == VR_ANTI_RANGE)
 	return NULL_TREE;
 
       /* These comparisons are never statically computable.  */
@@ -1490,7 +1474,7 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 
       /* Equality can be computed only between a range and an
 	 anti-range.  ~[VAL1, VAL2] == [VAL1, VAL2] is always false.  */
-      if (vr0->type == VR_RANGE)
+      if (vr0->kind () == VR_RANGE)
 	{
 	  /* To simplify processing, make VR0 the anti-range.  */
 	  value_range *tmp = vr0;
@@ -1500,8 +1484,8 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 
       gcc_assert (comp == NE_EXPR || comp == EQ_EXPR);
 
-      if (compare_values_warnv (vr0->min, vr1->min, strict_overflow_p) == 0
-	  && compare_values_warnv (vr0->max, vr1->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr0->min (), vr1->min (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr0->max (), vr1->max (), strict_overflow_p) == 0)
 	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -1519,12 +1503,12 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
     {
       /* Equality may only be computed if both ranges represent
 	 exactly one value.  */
-      if (compare_values_warnv (vr0->min, vr0->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr1->min, vr1->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr0->min (), vr0->max (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr1->min (), vr1->max (), strict_overflow_p) == 0)
 	{
-	  int cmp_min = compare_values_warnv (vr0->min, vr1->min,
+	  int cmp_min = compare_values_warnv (vr0->min (), vr1->min (),
 					      strict_overflow_p);
-	  int cmp_max = compare_values_warnv (vr0->max, vr1->max,
+	  int cmp_max = compare_values_warnv (vr0->max (), vr1->max (),
 					      strict_overflow_p);
 	  if (cmp_min == 0 && cmp_max == 0)
 	    return boolean_true_node;
@@ -1532,9 +1516,9 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 	    return boolean_false_node;
 	}
       /* If [V0_MIN, V1_MAX] < [V1_MIN, V1_MAX] then V0 != V1.  */
-      else if (compare_values_warnv (vr0->min, vr1->max,
+      else if (compare_values_warnv (vr0->min (), vr1->max (),
 				     strict_overflow_p) == 1
-	       || compare_values_warnv (vr1->min, vr0->max,
+	       || compare_values_warnv (vr1->min (), vr0->max (),
 					strict_overflow_p) == 1)
 	return boolean_false_node;
 
@@ -1549,20 +1533,20 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 	 make sure that both comparisons yield similar results to
 	 avoid comparing values that cannot be compared at
 	 compile-time.  */
-      cmp1 = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
-      cmp2 = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
+      cmp1 = compare_values_warnv (vr0->max (), vr1->min (), strict_overflow_p);
+      cmp2 = compare_values_warnv (vr0->min (), vr1->max (), strict_overflow_p);
       if ((cmp1 == -1 && cmp2 == -1) || (cmp1 == 1 && cmp2 == 1))
 	return boolean_true_node;
 
       /* If VR0 and VR1 represent a single value and are identical,
 	 return false.  */
-      else if (compare_values_warnv (vr0->min, vr0->max,
+      else if (compare_values_warnv (vr0->min (), vr0->max (),
 				     strict_overflow_p) == 0
-	       && compare_values_warnv (vr1->min, vr1->max,
+	       && compare_values_warnv (vr1->min (), vr1->max (),
 					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->min, vr1->min,
+	       && compare_values_warnv (vr0->min (), vr1->min (),
 					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->max, vr1->max,
+	       && compare_values_warnv (vr0->max (), vr1->max (),
 					strict_overflow_p) == 0)
 	return boolean_false_node;
 
@@ -1575,13 +1559,13 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
       int tst;
 
       /* If VR0 is to the left of VR1, return true.  */
-      tst = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
+      tst = compare_values_warnv (vr0->max (), vr1->min (), strict_overflow_p);
       if ((comp == LT_EXPR && tst == -1)
 	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
 	return boolean_true_node;
 
       /* If VR0 is to the right of VR1, return false.  */
-      tst = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
+      tst = compare_values_warnv (vr0->min (), vr1->max (), strict_overflow_p);
       if ((comp == LT_EXPR && (tst == 0 || tst == 1))
 	  || (comp == LE_EXPR && tst == 1))
 	return boolean_false_node;
@@ -1605,11 +1589,11 @@ static tree
 compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 			  bool *strict_overflow_p)
 {
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+  if (vr->varying_p () || vr->undefined_p ())
     return NULL_TREE;
 
   /* Anti-ranges need to be handled separately.  */
-  if (vr->type == VR_ANTI_RANGE)
+  if (vr->kind () == VR_ANTI_RANGE)
     {
       /* For anti-ranges, the only predicates that we can compute at
 	 compile time are equality and inequality.  */
@@ -1620,7 +1604,7 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 	return NULL_TREE;
 
       /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2.  */
-      if (value_inside_range (val, vr->min, vr->max) == 1)
+      if (value_inside_range (val, vr->min (), vr->max ()) == 1)
 	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -1630,16 +1614,16 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
     {
       /* EQ_EXPR may only be computed if VR represents exactly
 	 one value.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr->min (), vr->max (), strict_overflow_p) == 0)
 	{
-	  int cmp = compare_values_warnv (vr->min, val, strict_overflow_p);
+	  int cmp = compare_values_warnv (vr->min (), val, strict_overflow_p);
 	  if (cmp == 0)
 	    return boolean_true_node;
 	  else if (cmp == -1 || cmp == 1 || cmp == 2)
 	    return boolean_false_node;
 	}
-      else if (compare_values_warnv (val, vr->min, strict_overflow_p) == -1
-	       || compare_values_warnv (vr->max, val, strict_overflow_p) == -1)
+      else if (compare_values_warnv (val, vr->min (), strict_overflow_p) == -1
+	       || compare_values_warnv (vr->max (), val, strict_overflow_p) == -1)
 	return boolean_false_node;
 
       return NULL_TREE;
@@ -1647,14 +1631,14 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
   else if (comp == NE_EXPR)
     {
       /* If VAL is not inside VR, then they are always different.  */
-      if (compare_values_warnv (vr->max, val, strict_overflow_p) == -1
-	  || compare_values_warnv (vr->min, val, strict_overflow_p) == 1)
+      if (compare_values_warnv (vr->max (), val, strict_overflow_p) == -1
+	  || compare_values_warnv (vr->min (), val, strict_overflow_p) == 1)
 	return boolean_true_node;
 
       /* If VR represents exactly one value equal to VAL, then return
 	 false.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr->min, val, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr->min (), vr->max (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr->min (), val, strict_overflow_p) == 0)
 	return boolean_false_node;
 
       /* Otherwise, they may or may not be different.  */
@@ -1665,13 +1649,13 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
       int tst;
 
       /* If VR is to the left of VAL, return true.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->max (), val, strict_overflow_p);
       if ((comp == LT_EXPR && tst == -1)
 	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
 	return boolean_true_node;
 
       /* If VR is to the right of VAL, return false.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->min (), val, strict_overflow_p);
       if ((comp == LT_EXPR && (tst == 0 || tst == 1))
 	  || (comp == LE_EXPR && tst == 1))
 	return boolean_false_node;
@@ -1684,13 +1668,13 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
       int tst;
 
       /* If VR is to the right of VAL, return true.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->min (), val, strict_overflow_p);
       if ((comp == GT_EXPR && tst == 1)
 	  || (comp == GE_EXPR && (tst == 0 || tst == 1)))
 	return boolean_true_node;
 
       /* If VR is to the left of VAL, return false.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->max (), val, strict_overflow_p);
       if ((comp == GT_EXPR && (tst == -1 || tst == 0))
 	  || (comp == GE_EXPR && tst == -1))
 	return boolean_false_node;
@@ -1714,7 +1698,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 
   /* TODO.  Don't adjust anti-ranges.  An anti-range may provide
      better opportunities than a regular range, but I'm not sure.  */
-  if (vr->type == VR_ANTI_RANGE)
+  if (vr->kind () == VR_ANTI_RANGE)
     return;
 
   chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
@@ -1722,7 +1706,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   /* Like in PR19590, scev can return a constant function.  */
   if (is_gimple_min_invariant (chrec))
     {
-      set_value_range_to_value (vr, chrec, vr->equiv);
+      set_value_range_to_value (vr, chrec, vr->equiv ());
       return;
     }
 
@@ -1771,7 +1755,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   if (TREE_CODE (step) == INTEGER_CST
       && is_gimple_val (init)
       && (TREE_CODE (init) != SSA_NAME
-	  || get_value_range (init)->type == VR_RANGE))
+	  || get_value_range (init)->kind () == VR_RANGE))
     {
       widest_int nit;
 
@@ -1779,7 +1763,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	 the number of latch executions is the correct thing to use.  */
       if (max_loop_iterations (loop, &nit))
 	{
-	  value_range maxvr = VR_INITIALIZER;
+	  value_range maxvr;
 	  signop sgn = TYPE_SIGN (TREE_TYPE (step));
 	  wi::overflow_type overflow;
 
@@ -1799,9 +1783,9 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	      extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
 					      TREE_TYPE (init), init, tem);
 	      /* Likewise if the addition did.  */
-	      if (maxvr.type == VR_RANGE)
+	      if (maxvr.kind () == VR_RANGE)
 		{
-		  value_range initvr = VR_INITIALIZER;
+		  value_range initvr;
 
 		  if (TREE_CODE (init) == SSA_NAME)
 		    initvr = *(get_value_range (init));
@@ -1815,19 +1799,19 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 		     because the loop may exit immediately.  Overflow could
 		     happen in the plus expression in this case.  */
 		  if ((dir == EV_DIR_DECREASES
-		       && compare_values (maxvr.min, initvr.min) != -1)
+		       && compare_values (maxvr.min (), initvr.min ()) != -1)
 		      || (dir == EV_DIR_GROWS
-			  && compare_values (maxvr.max, initvr.max) != 1))
+			  && compare_values (maxvr.max (), initvr.max ()) != 1))
 		    return;
 
-		  tmin = maxvr.min;
-		  tmax = maxvr.max;
+		  tmin = maxvr.min ();
+		  tmax = maxvr.max ();
 		}
 	    }
 	}
     }
 
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+  if (vr->varying_p () || vr->undefined_p ())
     {
       min = tmin;
       max = tmax;
@@ -1840,15 +1824,15 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
       else
 	min = init;
     }
-  else if (vr->type == VR_RANGE)
+  else if (vr->kind () == VR_RANGE)
     {
-      min = vr->min;
-      max = vr->max;
+      min = vr->min ();
+      max = vr->max ();
 
       if (dir == EV_DIR_DECREASES)
 	{
-	  /* INIT is the maximum value.  If INIT is lower than VR->MAX
-	     but no smaller than VR->MIN, set VR->MAX to INIT.  */
+	  /* INIT is the maximum value.  If INIT is lower than VR->MAX ()
+	     but no smaller than VR->MIN (), set VR->MAX () to INIT.  */
 	  if (compare_values (init, max) == -1)
 	    max = init;
 
@@ -1860,7 +1844,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	}
       else
 	{
-	  /* If INIT is bigger than VR->MIN, set VR->MIN to INIT.  */
+	  /* If INIT is bigger than VR->MIN (), set VR->MIN () to INIT.  */
 	  if (compare_values (init, min) == 1)
 	    min = init;
 
@@ -1886,7 +1870,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   if (TREE_OVERFLOW_P (max))
     max = drop_tree_overflow (max);
 
-  set_value_range (vr, VR_RANGE, min, max, vr->equiv);
+  set_value_range (vr, VR_RANGE, min, max, vr->equiv ());
 }
 
 /* Dump value ranges of all SSA_NAMEs to FILE.  */
@@ -1957,11 +1941,11 @@ vrp_valueize (tree name)
   if (TREE_CODE (name) == SSA_NAME)
     {
       value_range *vr = x_vr_values->get_value_range (name);
-      if (vr->type == VR_RANGE
-	  && (TREE_CODE (vr->min) == SSA_NAME
-	      || is_gimple_min_invariant (vr->min))
-	  && vrp_operand_equal_p (vr->min, vr->max))
-	return vr->min;
+      if (vr->kind () == VR_RANGE
+	  && (TREE_CODE (vr->min ()) == SSA_NAME
+	      || is_gimple_min_invariant (vr->min ()))
+	  && vrp_operand_equal_p (vr->min (), vr->max ()))
+	return vr->min ();
     }
   return name;
 }
@@ -1982,8 +1966,9 @@ vrp_valueize_1 (tree name)
 	  && prop_simulate_again_p (def_stmt))
 	return NULL_TREE;
       value_range *vr = x_vr_values->get_value_range (name);
-      if (range_int_cst_singleton_p (vr))
-	return vr->min;
+      tree singleton;
+      if ((singleton = vr->singleton_p ()))
+	return singleton;
     }
   return name;
 }
@@ -2066,12 +2051,8 @@ vr_values::get_vr_for_comparison (int i)
   /* If name N_i does not have a valid range, use N_i as its own
      range.  This allows us to compare against names that may
      have N_i in their ranges.  */
-  if (vr.type == VR_VARYING || vr.type == VR_UNDEFINED)
-    {
-      vr.type = VR_RANGE;
-      vr.min = ssa_name (i);
-      vr.max = ssa_name (i);
-    }
+  if (vr.varying_p () || vr.undefined_p ())
+    vr = value_range (VR_RANGE, ssa_name (i), ssa_name (i), NULL);
 
   return vr;
 }
@@ -2094,7 +2075,7 @@ vr_values::compare_name_with_value (enum tree_code comp, tree var, tree val,
   value_range equiv_vr;
 
   /* Get the set of equivalences for VAR.  */
-  e = get_value_range (var)->equiv;
+  e = get_value_range (var)->equiv ();
 
   /* Start at -1.  Set it to 0 if we do a comparison without relying
      on overflow, or 1 if all comparisons rely on overflow.  */
@@ -2180,8 +2161,8 @@ vr_values::compare_names (enum tree_code comp, tree n1, tree n2,
 
   /* Compare the ranges of every name equivalent to N1 against the
      ranges of every name equivalent to N2.  */
-  e1 = get_value_range (n1)->equiv;
-  e2 = get_value_range (n2)->equiv;
+  e1 = get_value_range (n1)->equiv ();
+  e2 = get_value_range (n2)->equiv ();
 
   /* Use the fake bitmaps if e1 or e2 are not available.  */
   if (s_obstack == NULL)
@@ -2440,10 +2421,10 @@ vr_values::vrp_evaluate_conditional (tree_code code, tree op0,
       tree type = TREE_TYPE (op0);
       value_range *vr0 = get_value_range (op0);
 
-      if (vr0->type == VR_RANGE
+      if (vr0->kind () == VR_RANGE
 	  && INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_min (vr0->min)
-	  && vrp_val_is_max (vr0->max)
+	  && vrp_val_is_min (vr0->min ())
+	  && vrp_val_is_max (vr0->max ())
 	  && is_gimple_min_invariant (op1))
 	{
 	  location_t location;
@@ -2572,9 +2553,9 @@ find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
   unsigned int n = gimple_switch_num_labels (stmt);
   bool take_default;
   tree case_low, case_high;
-  tree min = vr->min, max = vr->max;
+  tree min = vr->min (), max = vr->max ();
 
-  gcc_checking_assert (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE);
+  gcc_checking_assert (!vr->varying_p () && !vr->undefined_p ());
 
   take_default = !find_case_label_range (stmt, min, max, &i, &j);
 
@@ -2582,7 +2563,7 @@ find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
   *min_idx2 = 1;
   *max_idx2 = 0;
 
-  if (vr->type == VR_RANGE)
+  if (vr->kind () == VR_RANGE)
     {
       *min_idx1 = i;
       *max_idx1 = j;
@@ -2663,9 +2644,9 @@ vr_values::vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
       fprintf (dump_file, "\n");
     }
 
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || symbolic_range_p (vr))
+  if (vr->undefined_p ()
+      || vr->varying_p ()
+      || vr->symbolic_p ())
     return;
 
   /* Find the single edge that is taken from the switch expression.  */
@@ -2809,40 +2790,24 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 		 See PR53465 and PR54767.  */
 	      if (e->flags & EDGE_DFS_BACK)
 		{
-		  if (vr_arg.type == VR_RANGE
-		      || vr_arg.type == VR_ANTI_RANGE)
-		    {
-		      vr_arg.equiv = NULL;
-		      if (symbolic_range_p (&vr_arg))
-			{
-			  vr_arg.type = VR_VARYING;
-			  vr_arg.min = NULL_TREE;
-			  vr_arg.max = NULL_TREE;
-			}
-		    }
-		}
-	      else
-		{
-		  /* If the non-backedge arguments range is VR_VARYING then
-		     we can still try recording a simple equivalence.  */
-		  if (vr_arg.type == VR_VARYING)
+		  if (!vr_arg.varying_p () && !vr_arg.undefined_p ())
 		    {
-		      vr_arg.type = VR_RANGE;
-		      vr_arg.min = arg;
-		      vr_arg.max = arg;
-		      vr_arg.equiv = NULL;
+		      vr_arg.equiv_clear ();
+		      if (vr_arg.symbolic_p ())
+			vr_arg.set_varying ();
 		    }
 		}
+	      /* If the non-backedge arguments range is VR_VARYING then
+		 we can still try recording a simple equivalence.  */
+	      else if (vr_arg.varying_p ())
+		vr_arg = value_range (VR_RANGE, arg, arg, NULL);
 	    }
 	  else
 	    {
 	      if (TREE_OVERFLOW_P (arg))
 		arg = drop_tree_overflow (arg);
 
-	      vr_arg.type = VR_RANGE;
-	      vr_arg.min = arg;
-	      vr_arg.max = arg;
-	      vr_arg.equiv = NULL;
+	      vr_arg = value_range (VR_RANGE, arg, arg);
 	    }
 
 	  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2855,19 +2820,19 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 	    }
 
 	  if (first)
-	    copy_value_range (vr_result, &vr_arg);
+	    vr_result->deep_copy (&vr_arg);
 	  else
-	    vrp_meet (vr_result, &vr_arg);
+	    vr_result->union_ (&vr_arg);
 	  first = false;
 
-	  if (vr_result->type == VR_VARYING)
+	  if (vr_result->varying_p ())
 	    break;
 	}
     }
 
-  if (vr_result->type == VR_VARYING)
+  if (vr_result->varying_p ())
     goto varying;
-  else if (vr_result->type == VR_UNDEFINED)
+  else if (vr_result->undefined_p ())
     goto update_range;
 
   old_edges = vr_phi_edge_counts[SSA_NAME_VERSION (lhs)];
@@ -2883,21 +2848,21 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
   if (edges > 0
       && gimple_phi_num_args (phi) > 1
       && edges == old_edges
-      && lhs_vr->type != VR_UNDEFINED
+      && !lhs_vr->undefined_p ()
       && may_simulate_backedge_again)
     {
       /* Compare old and new ranges, fall back to varying if the
          values are not comparable.  */
-      int cmp_min = compare_values (lhs_vr->min, vr_result->min);
+      int cmp_min = compare_values (lhs_vr->min (), vr_result->min ());
       if (cmp_min == -2)
 	goto varying;
-      int cmp_max = compare_values (lhs_vr->max, vr_result->max);
+      int cmp_max = compare_values (lhs_vr->max (), vr_result->max ());
       if (cmp_max == -2)
 	goto varying;
 
       /* For non VR_RANGE or for pointers fall back to varying if
 	 the range changed.  */
-      if ((lhs_vr->type != VR_RANGE || vr_result->type != VR_RANGE
+      if ((lhs_vr->kind () != VR_RANGE || vr_result->kind () != VR_RANGE
 	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
 	  && (cmp_min != 0 || cmp_max != 0))
 	goto varying;
@@ -2910,24 +2875,27 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 	 times to reach -INF.  Going to -INF + 1 also lets the following
 	 iteration compute whether there will be any overflow, at the
 	 expense of one additional iteration.  */
+      tree new_min = vr_result->min ();
+      tree new_max = vr_result->max ();
       if (cmp_min < 0)
-	vr_result->min = lhs_vr->min;
+	new_min = lhs_vr->min ();
       else if (cmp_min > 0
-	       && !vrp_val_is_min (vr_result->min))
-	vr_result->min
-	  = int_const_binop (PLUS_EXPR,
-			     vrp_val_min (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
+	       && !vrp_val_is_min (vr_result->min ()))
+	new_min = int_const_binop (PLUS_EXPR,
+				   vrp_val_min (vr_result->type ()),
+				   build_int_cst (vr_result->type (), 1));
 
       /* Similarly for the maximum value.  */
       if (cmp_max > 0)
-	vr_result->max = lhs_vr->max;
+	new_max = lhs_vr->max ();
       else if (cmp_max < 0
-	       && !vrp_val_is_max (vr_result->max))
-	vr_result->max
-	  = int_const_binop (MINUS_EXPR,
-			     vrp_val_max (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
+	       && !vrp_val_is_max (vr_result->max ()))
+	new_max = int_const_binop (MINUS_EXPR,
+				   vrp_val_max (vr_result->type ()),
+				   build_int_cst (vr_result->type (), 1));
+
+      *vr_result = value_range (vr_result->kind (), new_min, new_max,
+				vr_result->equiv ());
 
       /* If we dropped either bound to +-INF then if this is a loop
 	 PHI node SCEV may known more about its value-range.  */
@@ -2957,9 +2925,9 @@ infinite_check:
   /* If we will end up with a (-INF, +INF) range, set it to
      VARYING.  Same if the previous max value was invalid for
      the type and we end up with vr_result.min > vr_result.max.  */
-  if ((vr_result->type == VR_RANGE || vr_result->type == VR_ANTI_RANGE)
-      && !((vrp_val_is_max (vr_result->max) && vrp_val_is_min (vr_result->min))
-	   || compare_values (vr_result->min, vr_result->max) > 0))
+  if ((!vr_result->varying_p () && !vr_result->undefined_p ())
+      && !((vrp_val_is_max (vr_result->max ()) && vrp_val_is_min (vr_result->min ()))
+	   || compare_values (vr_result->min (), vr_result->max ()) > 0))
     ;
   else
     set_value_range_to_varying (vr_result);
@@ -3071,8 +3039,8 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
       vr = get_value_range (op0);
       if (range_int_cst_p (vr))
 	{
-	  op0min = vr->min;
-	  op0max = vr->max;
+	  op0min = vr->min ();
+	  op0max = vr->max ();
 	}
     }
 
@@ -3081,7 +3049,7 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
     {
       value_range *vr1 = get_value_range (op1);
       if (range_int_cst_p (vr1))
-	op1min = vr1->min;
+	op1min = vr1->min ();
     }
   if (rhs_code == TRUNC_MOD_EXPR
       && TREE_CODE (op1min) == INTEGER_CST
@@ -3285,8 +3253,7 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
   tree op0 = gimple_assign_rhs1 (stmt);
   tree op1 = gimple_assign_rhs2 (stmt);
   tree op = NULL_TREE;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
+  value_range vr0, vr1;
   wide_int may_be_nonzero0, may_be_nonzero1;
   wide_int must_be_nonzero0, must_be_nonzero1;
   wide_int mask;
@@ -3405,10 +3372,10 @@ test_for_singularity (enum tree_code cond_code, tree op0,
      value range information we have for op0.  */
   if (min && max)
     {
-      if (compare_values (vr->min, min) == 1)
-	min = vr->min;
-      if (compare_values (vr->max, max) == -1)
-	max = vr->max;
+      if (compare_values (vr->min (), min) == 1)
+	min = vr->min ();
+      if (compare_values (vr->max (), max) == -1)
+	max = vr->max ();
 
       /* If the new min/max values have converged to a single value,
 	 then there is only one value which can satisfy the condition,
@@ -3431,14 +3398,14 @@ range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
   signop src_sgn;
 
   /* We can only handle integral and pointer types.  */
-  src_type = TREE_TYPE (vr->min);
+  src_type = vr->type ();
   if (!INTEGRAL_TYPE_P (src_type)
       && !POINTER_TYPE_P (src_type))
     return false;
 
   /* An extension is fine unless VR is SIGNED and dest_sgn is UNSIGNED,
      and so is an identity transform.  */
-  src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
+  src_precision = TYPE_PRECISION (vr->type ());
   src_sgn = TYPE_SIGN (src_type);
   if ((src_precision < dest_precision
        && !(dest_sgn == UNSIGNED && src_sgn == SIGNED))
@@ -3446,9 +3413,7 @@ range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
     return true;
 
   /* Now we can only handle ranges with constant bounds.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (!range_int_cst_p (vr))
     return false;
 
   /* For sign changes, the MSB of the wide_int has to be clear.
@@ -3456,17 +3421,17 @@ range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
      a signed wide_int, while a negative value cannot be represented
      by an unsigned wide_int.  */
   if (src_sgn != dest_sgn
-      && (wi::lts_p (wi::to_wide (vr->min), 0)
-	  || wi::lts_p (wi::to_wide (vr->max), 0)))
+      && (wi::lts_p (wi::to_wide (vr->min ()), 0)
+	  || wi::lts_p (wi::to_wide (vr->max ()), 0)))
     return false;
 
   /* Then we can perform the conversion on both ends and compare
      the result for equality.  */
-  tem = wi::ext (wi::to_widest (vr->min), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->min))
+  tem = wi::ext (wi::to_widest (vr->min ()), dest_precision, dest_sgn);
+  if (tem != wi::to_widest (vr->min ()))
     return false;
-  tem = wi::ext (wi::to_widest (vr->max), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->max))
+  tem = wi::ext (wi::to_widest (vr->max ()), dest_precision, dest_sgn);
+  if (tem != wi::to_widest (vr->max ()))
     return false;
 
   return true;
@@ -3493,7 +3458,7 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
 
       /* If we have range information for OP0, then we might be
 	 able to simplify this conditional. */
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  tree new_tree = test_for_singularity (cond_code, op0, op1, vr);
 	  if (new_tree)
@@ -3636,9 +3601,9 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
       vr = get_value_range (op);
 
       /* We can only handle integer ranges.  */
-      if ((vr->type != VR_RANGE
-	   && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->varying_p ()
+	  || vr->undefined_p ()
+	  || vr->symbolic_p ())
 	return false;
 
       /* Find case label for min/max of the value range.  */
@@ -3666,7 +3631,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
      value range.  */
   size_t min_idx = 1, max_idx = 0;
   if (vr != NULL)
-    find_case_label_range (stmt, vr->min, vr->max, &min_idx, &max_idx);
+    find_case_label_range (stmt, vr->min (), vr->max (), &min_idx, &max_idx);
   if (min_idx <= max_idx)
     {
       tree min_label = gimple_switch_label (stmt, min_idx);
@@ -3674,10 +3639,10 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
 
       /* Avoid changing the type of the case labels when truncating.  */
       tree case_label_type = TREE_TYPE (CASE_LOW (min_label));
-      tree vr_min = fold_convert (case_label_type, vr->min);
-      tree vr_max = fold_convert (case_label_type, vr->max);
+      tree vr_min = fold_convert (case_label_type, vr->min ());
+      tree vr_max = fold_convert (case_label_type, vr->max ());
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  /* If OP's value range is [2,8] and the low label range is
 	     0 ... 3, truncate the label's range to 2 .. 3.  */
@@ -3693,7 +3658,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
 	      && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0)
 	    CASE_HIGH (max_label) = vr_max;
 	}
-      else if (vr->type == VR_ANTI_RANGE)
+      else if (vr->kind () == VR_ANTI_RANGE)
 	{
 	  tree one_cst = build_one_cst (case_label_type);
 
@@ -3930,9 +3895,7 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
   gassign *conv;
 
   /* We can only handle constant ranges.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (!range_int_cst_p (vr))
     return false;
 
   /* First check if we can use a signed type in place of an unsigned.  */
@@ -4088,26 +4051,26 @@ bool
 vr_values::two_valued_val_range_p (tree var, tree *a, tree *b)
 {
   value_range *vr = get_value_range (var);
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (vr->varying_p ()
+      || vr->undefined_p ()
+      || TREE_CODE (vr->min ()) != INTEGER_CST
+      || TREE_CODE (vr->max ()) != INTEGER_CST)
     return false;
 
-  if (vr->type == VR_RANGE
-      && wi::to_wide (vr->max) - wi::to_wide (vr->min) == 1)
+  if (vr->kind () == VR_RANGE
+      && wi::to_wide (vr->max ()) - wi::to_wide (vr->min ()) == 1)
     {
-      *a = vr->min;
-      *b = vr->max;
+      *a = vr->min ();
+      *b = vr->max ();
       return true;
     }
 
   /* ~[TYPE_MIN + 1, TYPE_MAX - 1] */
-  if (vr->type == VR_ANTI_RANGE
-      && (wi::to_wide (vr->min)
+  if (vr->kind () == VR_ANTI_RANGE
+      && (wi::to_wide (vr->min ())
 	  - wi::to_wide (vrp_val_min (TREE_TYPE (var)))) == 1
       && (wi::to_wide (vrp_val_max (TREE_TYPE (var)))
-	  - wi::to_wide (vr->max)) == 1)
+	  - wi::to_wide (vr->max ())) == 1)
     {
       *a = vrp_val_min (TREE_TYPE (var));
       *b = vrp_val_max (TREE_TYPE (var));
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 487a800c1ea..496707856c3 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -72,7 +72,7 @@ class vr_values
   void cleanup_edges_and_switches (void);
 
  private:
-  void add_equivalence (bitmap *, const_tree);
+  bitmap add_equivalence (bitmap, const_tree);
   bool vrp_stmt_computes_nonzero (gimple *);
   bool op_with_boolean_value_range_p (tree);
   bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);
@@ -142,7 +142,5 @@ class vr_values
   vec<switch_update> to_update_switch_stmts;
 };
 
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
-
 extern tree get_output_for_vrp (gimple *);
 #endif /* GCC_VR_VALUES_H */
Richard Biener Oct. 11, 2018, 9:47 a.m. | #3
On Thu, Oct 11, 2018 at 10:19 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> Hi Richard.  Thanks for reviewing.
>
> On 10/10/18 6:27 AM, Richard Biener wrote:
> > On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
> >>
> >> I'm assuming the silence on the RFC means nobody is viscerally opposed
> >> to it, so here goes the actual implementation ;-).
> >>
> >>          FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
> >>
> >> My aim is no change to the current functionality, but there are some
> >> things that changed slightly (with no appreciable change in
> >> bootstrapability or tests).
> >>
> >> 1.  Primarily, we were building value_ranges by modifying them in-flight
> >> with no regards to the validity of the resulting range.  By enforcing
> >> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
> >> left the equivalence bits uncleared.  This comment in the original
> >> header file indicates that this is invalid behavior:
> >>
> >>     /* Set of SSA names whose value ranges are equivalent to this one.
> >>        This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
> >>
> >> The API now enforces this upon construction.
> >>
> >> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
> >> This is invalid.  Although these values were being ignored, the API now
> >> enforces this.
> >>
> >> 3. I saw one case in set_value_range_with_overflow() were we were
> >> building an invalid range with swapped ranges, where we were silently
> >> depending on somebody further up the call chain to swap them for us.
> >> I've fixed this at creation.
> >>
> >> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
> >> left as proof that the original VR_UNDEFINED set was not necessary, as
> >> it is now done by default on an empty constructor:
> >>
> >> -  void init () { m_vr.type = VR_UNDEFINED; }
> >> +  void init () { gcc_assert (m_vr.undefined_p ()); }
> >>
> >> One last note.  The file tree-vrp.c already has a cripple API of sorts
> >> in the form of functions (set_value_range_to_varying, etc).  I have
> >> tried to keep those functions available, by calling the API under the
> >> covers, but would be okay in removing them altogether as a follow-up.
> >>
> >> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
> >> new tree type field.
> >>
> >> I am quoting the class declaration below to make it easy to review at a
> >> high level.
> >>
> >> Tested on x86-64 Linux.  All languages, including Ada and Go.
> >>
> >> OK for trunk?
> >
> > Reviewing in patch order.
> >
> >> Aldy
> >>
> >> class GTY((for_user)) value_range
> >> {
> >>    public:
> >>     value_range ();
> >>     value_range (tree type);
> >>     value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
> >>     bool operator== (const value_range &) const;
> >>     bool operator!= (const value_range &) const;
> >>     void intersect (const value_range *);
> >>     void union_ (const value_range *);
> >
> > with trailing underscore?  seriously?
>
> Hey!  You complained about Union() last year, at which point the
> consensus was that trailing underscores would be ok for symbol names
> that clashed with keywords.

;)

I also thought about union_into / union_with.  As opposed to a hypothetical

  value_range union (const value_range& a, const value_range& b)

function.

> And yes, it was also discussed whether we should overload | and ^ for
> union and intersection, but was denied for readability and what have yous.
>
> >
> >>     /* Like operator== but ignore equivalence bitmap.  */
> >>     bool ignore_equivs_equal_p (const value_range &) const;
> >>     /* Like a operator= but update equivalence bitmap efficiently.  */
> >>     void copy_with_equiv_update (const value_range *);
> >>
> >>     /* Types of value ranges.  */
> >>     bool undefined_p () const;
> >>     bool varying_p () const;
> >>     bool symbolic_p () const;
> >>     bool numeric_p () const;
> >>     void set_undefined (tree = NULL);
> >>     void set_varying (tree = NULL);
> >
> > I'd appreciate comments on those predicates, esp. as you
> > replace positive tests by negative ones like in
>
> Done.
>
> >
> >     /* If we found any usable VR, set the VR to ssa_name and create a
> >        PUSH old value in the stack with the old VR.  */
> > -  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> > +  if (!vr.undefined_p () && !vr.varying_p ())
> >       {
> >
> > I'd also spell numeric_p as constant_p or drop it alltogether
> > since !symbolic_p should imply it given varying_p and undefined_p
> > are just some special-cases of "numeric_p" (full and empty range).
>
> Done.
>
> >
> > That said, for the time being I'd use non_symbolic_range_or_anti_range_p
> > instead of numeric_p () (seeing that you maybe want to hide the fact
> > that we have anti-ranges?)
>
> Errr... No.
>
> >
> > -  value_range vr = VR_INITIALIZER;
> > +  value_range vr (TREE_TYPE (name));
> >
> > so you basically forgo with the fact that empty ranges are universal?
> > I don't like it too much that we have to invent a type here.  Why enforce this
> > and not allow/force type == NULL_TREE for empty ranges?
> >
> > One could argue VARYING is also universal to some extent and useful
> > only with context, so similar argument applies to your change forcing
> > a type for set_value_range_to_varying.
> >
> > -      value_range vr = VR_INITIALIZER;
> > +      value_range vr;
> >
> > oh, so you do have a default constructor.
> >
> >>
> >>     /* Equivalence bitmap methods.  */
> >>     bitmap equiv () const;
> >>     void set_equiv (bitmap);
> >
> > Err, I think we've settled on _not_ wrapping all member accesses
> > with get/set methods, didn't we?  I personally dislike that very much.
> >
> >>     void equiv_free ();
> >>     void equiv_copy (const value_range *);
> >>     void equiv_clear ();
> >>     void equiv_and (const value_range *);
> >>     void equiv_ior (const value_range *);
> >
> > Likewise I find this useless abstraction.  It's even questionable
> > if _free/_clear/_copy are good APIs here.  This should be all
> > hidden in intersect/union which I do not find in the API at all...
>
> I missed that discussion.  We did?  I dislike exposing the internals.
> Abstracting things out makes it easier to change things in the future--
> or insert instrumenting code, or whatever.

OK, I might misremember and it's eventually just my personal taste
against slapping a setFoo/getFoo method in a class as the first
thing to do after adding a m_Foo member...

> That said, I have removed copy/free/and/or.  As you said, it was much
> easier to make the details internal to the intersect/union member functions.
>
> However, I have kept:
>
>    bitmap equiv () const;
>    void set_equiv (bitmap);
>    void equiv_clear ();
>
> I think we can get away with just having a clear, instead of a free, as
> it's all in an obstack and there doesn't seem to be any consistent use
> of free vs. clear throughout (except one or two, which I've kept).

Yeah.

> Also, we don't really need to expose set_equiv(), but for its one use in
> vr_values::add_equivalence().  One option could be to make vr_values and
> value_ranges friends and let add_equivalence touch m_equiv.  But that's
> a bit heavy handed.
>
> Or we could add this to the API instead of set_equiv():
>
> void
> value_range::add_equivalence (bitmap_obstack obstack, tree var)
> {
> }
>
> I don't know how I feel about passing the obtack, or including
> "bitmap.h" from everywhere tree-vrp.h is used (that is, everywhere).

Equivalences are evil ;)  But I guess passing in the obstack works
for me.  Maybe as trailing argument, defaulted to NULL in which
case we use the default bitmap obstack?

> For equiv(), we could remove virtually all of its uses, since 99% of
> them are in the form:
>
>         set_value_range (vr, VR_SOMETHING, min, max, vr->equiv ())
>
> Instead we could We could provide:
>
>         vr->update (VR_SOMETHING, min, max);
>
> ...which is just like set_value_range, but keeping the equivalences intact.

Yep, sounds good.

>  > hidden in intersect/union which I do not find in the API at all...
>
> How could you, it was front and center ;-):
>
>    void intersect (const value_range *);
>    void union_ (const value_range *);

Missed that in the first review and then failed to delete that comment ;)

> >
> >>
> >>     /* Misc methods.  */
> >>     tree type () const;
> >
> > type() and vrtype() is confusing - value_type() and range_kind() maybe?
>
> How about we keep type(), since 99% of all uses of "type" in the
> compiler are "tree type", so it's easy to figure out.  And instead of
> range_kind() we use kind().  It's already obvious it's a range, so
> vr->kind() reads fine IMO.

Works for me.

> >
> >>     bool null_p () const;
> >>     bool may_contain_p (tree) const;
> >>     tree singleton () const;
> >
> > No documentation? :/   Why null_p but singleton (instead of singleton_p)?
>
> Documented.
>
> Singleton returns the singleton if found, otherwise returns NULL.
> NULL_P returns true/or false.  I thought the preferred way was for _p to
> always return booleans.

Ah, missed that "detail"...

> I don't feel strongly, so I've renamed it to singleton_p() since a
> NULL_TREE is as good as false.  Another option is:
>
>         bool singleton_p (tree *result = NULL)
>
> Hmmm...I like this last one.  What do you think?

Like it as well.

> >
> >>     void set_and_canonicalize (enum value_range_type, tree, tree, tree,
> >> bitmap);
> >
> > Why's that necessary if you enforce sanity?
>
> Canonicalize also does some optimizations like converting anti-ranges
> into ranges if possible.  Although I would be OK with putting that
> functionality in value_range::set() to be done on creation, I don't know
> how I feel about polluting the creation code with fixing swapped min/max:
>
>    /* Wrong order for min and max, to swap them and the VR type we need
>       to adjust them.  */
>
> It feels wrong to construct a range with swapped end-points, and hope
> things turn out ok.  ISTM that canonicalize() clearly specifies intent:
> I'm giving you a shitty range, fix it.
>
> Thoughts?

OK, let's keep it the way you had it.  I never liked this part very much
(even though I added it!).

> >
> >>     void dump () const;
> >>
> >>     /* Temporary accessors that should eventually be removed.  */
> >>     enum value_range_type vrtype () const;
> >>     tree min () const;
> >>     tree max () const;
> >>
> >>    private:
> >>     void set (value_range_type, tree type, tree, tree, bitmap);
> >>     void check ();
> >>     bool equal_p (const value_range &, bool ignore_equivs) const;
> >>
> >>     enum value_range_type m_vrtype;
> >>    public:
> >>     /* These should be private, but GTY is a piece of crap.  */
> >>     tree m_min;
> >>     tree m_max;
> >>     tree m_type;
> >
> > m_type is redundant (see above).
>
> Removed.
>
> Tested on x86-64 Linux.
>
> Aldy
>
> p.s. Oh yeah, it wouldn't be an Aldy patch without an irrelevant bit
> added for good measure:
>
> +void
> +bitmap_head::dump ()
> +{
> +  debug (this);
> +}
>
> I find having ->dump() available for each and every structure in GCC
> helpful in debugging.  At some point we should standardize on dump(FILE
> *) and debug() to dump to stderr.  But alas, there are too many dump()'s
> that already dump to stderr :-/.

FWIW I like

void dump (const bitmap_head&);

more since it doesn't clutter the APIs and can theoretically be very
easily not built into a release compiler.  And IIRC we already have
global overloads of debug () for exactly the reason you cite.  Having
both styles is IMHO not good.  (and I've stated my preference - feel
free to provide statistics for in-tree uses ;))

Richard.
Aldy Hernandez Oct. 11, 2018, 6:25 p.m. | #4
On 10/11/18 5:47 AM, Richard Biener wrote:
> On Thu, Oct 11, 2018 at 10:19 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>>
>> Hi Richard.  Thanks for reviewing.
>>
>> On 10/10/18 6:27 AM, Richard Biener wrote:
>>> On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>>>
>>>> I'm assuming the silence on the RFC means nobody is viscerally opposed
>>>> to it, so here goes the actual implementation ;-).
>>>>
>>>>           FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
>>>>
>>>> My aim is no change to the current functionality, but there are some
>>>> things that changed slightly (with no appreciable change in
>>>> bootstrapability or tests).
>>>>
>>>> 1.  Primarily, we were building value_ranges by modifying them in-flight
>>>> with no regards to the validity of the resulting range.  By enforcing
>>>> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
>>>> left the equivalence bits uncleared.  This comment in the original
>>>> header file indicates that this is invalid behavior:
>>>>
>>>>      /* Set of SSA names whose value ranges are equivalent to this one.
>>>>         This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
>>>>
>>>> The API now enforces this upon construction.
>>>>
>>>> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
>>>> This is invalid.  Although these values were being ignored, the API now
>>>> enforces this.
>>>>
>>>> 3. I saw one case in set_value_range_with_overflow() were we were
>>>> building an invalid range with swapped ranges, where we were silently
>>>> depending on somebody further up the call chain to swap them for us.
>>>> I've fixed this at creation.
>>>>
>>>> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
>>>> left as proof that the original VR_UNDEFINED set was not necessary, as
>>>> it is now done by default on an empty constructor:
>>>>
>>>> -  void init () { m_vr.type = VR_UNDEFINED; }
>>>> +  void init () { gcc_assert (m_vr.undefined_p ()); }
>>>>
>>>> One last note.  The file tree-vrp.c already has a cripple API of sorts
>>>> in the form of functions (set_value_range_to_varying, etc).  I have
>>>> tried to keep those functions available, by calling the API under the
>>>> covers, but would be okay in removing them altogether as a follow-up.
>>>>
>>>> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
>>>> new tree type field.
>>>>
>>>> I am quoting the class declaration below to make it easy to review at a
>>>> high level.
>>>>
>>>> Tested on x86-64 Linux.  All languages, including Ada and Go.
>>>>
>>>> OK for trunk?
>>>
>>> Reviewing in patch order.
>>>
>>>> Aldy
>>>>
>>>> class GTY((for_user)) value_range
>>>> {
>>>>     public:
>>>>      value_range ();
>>>>      value_range (tree type);
>>>>      value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
>>>>      bool operator== (const value_range &) const;
>>>>      bool operator!= (const value_range &) const;
>>>>      void intersect (const value_range *);
>>>>      void union_ (const value_range *);
>>>
>>> with trailing underscore?  seriously?
>>
>> Hey!  You complained about Union() last year, at which point the
>> consensus was that trailing underscores would be ok for symbol names
>> that clashed with keywords.
> 
> ;)
> 
> I also thought about union_into / union_with.  As opposed to a hypothetical
> 
>    value_range union (const value_range& a, const value_range& b)
> 
> function.
> 
>> And yes, it was also discussed whether we should overload | and ^ for
>> union and intersection, but was denied for readability and what have yous.
>>
>>>
>>>>      /* Like operator== but ignore equivalence bitmap.  */
>>>>      bool ignore_equivs_equal_p (const value_range &) const;
>>>>      /* Like a operator= but update equivalence bitmap efficiently.  */
>>>>      void copy_with_equiv_update (const value_range *);
>>>>
>>>>      /* Types of value ranges.  */
>>>>      bool undefined_p () const;
>>>>      bool varying_p () const;
>>>>      bool symbolic_p () const;
>>>>      bool numeric_p () const;
>>>>      void set_undefined (tree = NULL);
>>>>      void set_varying (tree = NULL);
>>>
>>> I'd appreciate comments on those predicates, esp. as you
>>> replace positive tests by negative ones like in
>>
>> Done.
>>
>>>
>>>      /* If we found any usable VR, set the VR to ssa_name and create a
>>>         PUSH old value in the stack with the old VR.  */
>>> -  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
>>> +  if (!vr.undefined_p () && !vr.varying_p ())
>>>        {
>>>
>>> I'd also spell numeric_p as constant_p or drop it alltogether
>>> since !symbolic_p should imply it given varying_p and undefined_p
>>> are just some special-cases of "numeric_p" (full and empty range).
>>
>> Done.
>>
>>>
>>> That said, for the time being I'd use non_symbolic_range_or_anti_range_p
>>> instead of numeric_p () (seeing that you maybe want to hide the fact
>>> that we have anti-ranges?)
>>
>> Errr... No.
>>
>>>
>>> -  value_range vr = VR_INITIALIZER;
>>> +  value_range vr (TREE_TYPE (name));
>>>
>>> so you basically forgo with the fact that empty ranges are universal?
>>> I don't like it too much that we have to invent a type here.  Why enforce this
>>> and not allow/force type == NULL_TREE for empty ranges?
>>>
>>> One could argue VARYING is also universal to some extent and useful
>>> only with context, so similar argument applies to your change forcing
>>> a type for set_value_range_to_varying.
>>>
>>> -      value_range vr = VR_INITIALIZER;
>>> +      value_range vr;
>>>
>>> oh, so you do have a default constructor.
>>>
>>>>
>>>>      /* Equivalence bitmap methods.  */
>>>>      bitmap equiv () const;
>>>>      void set_equiv (bitmap);
>>>
>>> Err, I think we've settled on _not_ wrapping all member accesses
>>> with get/set methods, didn't we?  I personally dislike that very much.
>>>
>>>>      void equiv_free ();
>>>>      void equiv_copy (const value_range *);
>>>>      void equiv_clear ();
>>>>      void equiv_and (const value_range *);
>>>>      void equiv_ior (const value_range *);
>>>
>>> Likewise I find this useless abstraction.  It's even questionable
>>> if _free/_clear/_copy are good APIs here.  This should be all
>>> hidden in intersect/union which I do not find in the API at all...
>>
>> I missed that discussion.  We did?  I dislike exposing the internals.
>> Abstracting things out makes it easier to change things in the future--
>> or insert instrumenting code, or whatever.
> 
> OK, I might misremember and it's eventually just my personal taste
> against slapping a setFoo/getFoo method in a class as the first
> thing to do after adding a m_Foo member...
> 
>> That said, I have removed copy/free/and/or.  As you said, it was much
>> easier to make the details internal to the intersect/union member functions.
>>
>> However, I have kept:
>>
>>     bitmap equiv () const;
>>     void set_equiv (bitmap);
>>     void equiv_clear ();
>>
>> I think we can get away with just having a clear, instead of a free, as
>> it's all in an obstack and there doesn't seem to be any consistent use
>> of free vs. clear throughout (except one or two, which I've kept).
> 
> Yeah.
> 
>> Also, we don't really need to expose set_equiv(), but for its one use in
>> vr_values::add_equivalence().  One option could be to make vr_values and
>> value_ranges friends and let add_equivalence touch m_equiv.  But that's
>> a bit heavy handed.
>>
>> Or we could add this to the API instead of set_equiv():
>>
>> void
>> value_range::add_equivalence (bitmap_obstack obstack, tree var)
>> {
>> }
>>
>> I don't know how I feel about passing the obtack, or including
>> "bitmap.h" from everywhere tree-vrp.h is used (that is, everywhere).
> 
> Equivalences are evil ;)  But I guess passing in the obstack works
> for me.  Maybe as trailing argument, defaulted to NULL in which
> case we use the default bitmap obstack?

Done.

> 
>> For equiv(), we could remove virtually all of its uses, since 99% of
>> them are in the form:
>>
>>          set_value_range (vr, VR_SOMETHING, min, max, vr->equiv ())
>>
>> Instead we could We could provide:
>>
>>          vr->update (VR_SOMETHING, min, max);
>>
>> ...which is just like set_value_range, but keeping the equivalences intact.
> 
> Yep, sounds good.

Done.

> 
>>   > hidden in intersect/union which I do not find in the API at all...
>>
>> How could you, it was front and center ;-):
>>
>>     void intersect (const value_range *);
>>     void union_ (const value_range *);
> 
> Missed that in the first review and then failed to delete that comment ;)
> 
>>>
>>>>
>>>>      /* Misc methods.  */
>>>>      tree type () const;
>>>
>>> type() and vrtype() is confusing - value_type() and range_kind() maybe?
>>
>> How about we keep type(), since 99% of all uses of "type" in the
>> compiler are "tree type", so it's easy to figure out.  And instead of
>> range_kind() we use kind().  It's already obvious it's a range, so
>> vr->kind() reads fine IMO.
> 
> Works for me.

Done.

> 
>>>
>>>>      bool null_p () const;
>>>>      bool may_contain_p (tree) const;
>>>>      tree singleton () const;
>>>
>>> No documentation? :/   Why null_p but singleton (instead of singleton_p)?
>>
>> Documented.
>>
>> Singleton returns the singleton if found, otherwise returns NULL.
>> NULL_P returns true/or false.  I thought the preferred way was for _p to
>> always return booleans.
> 
> Ah, missed that "detail"...
> 
>> I don't feel strongly, so I've renamed it to singleton_p() since a
>> NULL_TREE is as good as false.  Another option is:
>>
>>          bool singleton_p (tree *result = NULL)
>>
>> Hmmm...I like this last one.  What do you think?
> 
> Like it as well.

Done.

> 
>>>
>>>>      void set_and_canonicalize (enum value_range_type, tree, tree, tree,
>>>> bitmap);
>>>
>>> Why's that necessary if you enforce sanity?
>>
>> Canonicalize also does some optimizations like converting anti-ranges
>> into ranges if possible.  Although I would be OK with putting that
>> functionality in value_range::set() to be done on creation, I don't know
>> how I feel about polluting the creation code with fixing swapped min/max:
>>
>>     /* Wrong order for min and max, to swap them and the VR type we need
>>        to adjust them.  */
>>
>> It feels wrong to construct a range with swapped end-points, and hope
>> things turn out ok.  ISTM that canonicalize() clearly specifies intent:
>> I'm giving you a shitty range, fix it.
>>
>> Thoughts?
> 
> OK, let's keep it the way you had it.  I never liked this part very much
> (even though I added it!).

Sounds like you need to have a long talk with yourself ;-).

> 
>>>
>>>>      void dump () const;
>>>>
>>>>      /* Temporary accessors that should eventually be removed.  */
>>>>      enum value_range_type vrtype () const;
>>>>      tree min () const;
>>>>      tree max () const;
>>>>
>>>>     private:
>>>>      void set (value_range_type, tree type, tree, tree, bitmap);
>>>>      void check ();
>>>>      bool equal_p (const value_range &, bool ignore_equivs) const;
>>>>
>>>>      enum value_range_type m_vrtype;
>>>>     public:
>>>>      /* These should be private, but GTY is a piece of crap.  */
>>>>      tree m_min;
>>>>      tree m_max;
>>>>      tree m_type;
>>>
>>> m_type is redundant (see above).
>>
>> Removed.
>>
>> Tested on x86-64 Linux.
>>
>> Aldy
>>
>> p.s. Oh yeah, it wouldn't be an Aldy patch without an irrelevant bit
>> added for good measure:
>>
>> +void
>> +bitmap_head::dump ()
>> +{
>> +  debug (this);
>> +}
>>
>> I find having ->dump() available for each and every structure in GCC
>> helpful in debugging.  At some point we should standardize on dump(FILE
>> *) and debug() to dump to stderr.  But alas, there are too many dump()'s
>> that already dump to stderr :-/.
> 
> FWIW I like
> 
> void dump (const bitmap_head&);
> 
> more since it doesn't clutter the APIs and can theoretically be very
> easily not built into a release compiler.  And IIRC we already have
> global overloads of debug () for exactly the reason you cite.  Having
> both styles is IMHO not good.  (and I've stated my preference - feel
> free to provide statistics for in-tree uses ;))

Ughh, maybe in the future I'll sit down and convert everything to 
something regular.

Tested with all languages on x86-64 Linux.

OK for trunk?

Aldy
gcc/

	* bitmap.c (bitmap_head::dump): New.
	* bitmap.h (bitmap_head): Add dump().
	* gimple-ssa-evrp-analyze.c
	(evrp_range_analyzer::try_find_new_range): Adjust for value_range API.
	(evrp_range_analyzer::set_ssa_range_info): Same.
	(evrp_range_analyzer::record_ranges_from_phis): Same.
	(evrp_range_analyzer::record_ranges_from_stmt): Same.
	* gimple-ssa-evrp.c (evrp_dom_walker::before_dom_children): Same.
	* gimple-ssa-sprintf.c (get_int_range): Same.
	(format_integer): Same.
	(sprintf_dom_walker::handle_gimple_call): Same.
	* ipa-cp.c (ipcp_vr_lattice::meet_with_1): Same.
	(ipcp_vr_lattice::top_p): Same.
	(ipcp_vr_lattice::bottom_p): Same.
	(ipcp_vr_lattice::set_to_bottom): Same.
	(ipa_vr_operation_and_type_effects): Same.
	(propagate_vr_across_jump_function): Same.
	(ipcp_store_vr_results): Same.
	* ipa-prop.c (struct ipa_vr_ggc_hash_traits): Same.
	(ipa_print_node_jump_functions_for_edge): Same.
	(ipa_get_value_range): Same.
	(ipa_compute_jump_functions_for_edge): Same.
	(ipa_write_jump_function): Same.
	* tree-ssa-dom.c (simplify_stmt_for_jump_threading): Same.
	* tree-ssa-threadedge.c (record_temporary_equivalences_from_phis):
	Same.
	* vr-values.c (set_value_range_to_nonnegative): Same.
	(set_value_range_to_truthvalue): Same.
	(vr_values::get_value_range): Same.
	(vr_values::set_defs_to_varying): Same.
	(vr_values::update_value_range): Same.
	(symbolic_range_based_on_p): Same.
	(vr_values::op_with_boolean_value_range_p): Same.
	(vr_values::extract_range_for_var_from_comparison_expr): Same.
	(vr_values::extract_range_from_ssa_name): Same.
	(vr_values::extract_range_from_binary_expr): Same.
	(vr_values::extract_range_from_unary_expr): Same.
	(vr_values::extract_range_from_cond_expr): Same.
	(vr_values::extract_range_from_comparison): Same.
	(vr_values::check_for_binary_op_overflow): Same.
	(vr_values::extract_range_basic): Same.
	(vr_values::extract_range_from_assignment): Same.
	(compare_ranges): Same.
	(compare_range_with_value): Same.
	(vr_values::adjust_range_with_scev): Same.
	(vrp_valueize): Same.
	(vrp_valueize_1): Same.
	(vr_values::get_vr_for_comparison): Same.
	(vr_values::compare_name_with_value): Same.
	(vr_values::compare_names): Same.
	(vr_values::vrp_evaluate_conditional): Same.
	(find_case_label_ranges): Same.
	(vr_values::vrp_visit_switch_stmt): Same.
	(vr_values::extract_range_from_phi_node): Same.
	(vr_values::simplify_div_or_mod_using_ranges): Same.
	(vr_values::simplify_bit_ops_using_ranges): Same.
	(test_for_singularity): Same.
	(range_fits_type_p): Same.
	(vr_values::simplify_cond_using_ranges_1): Same.
	(vr_values::simplify_switch_using_ranges): Same.
	(vr_values::simplify_float_conversion_using_ranges): Same.
	(vr_values::two_valued_val_range_p): Same.
	(vr_values::add_equivalence): Move to value_range::equiv_add.
	* vr-values.h (vr_values::add_equivalence): Remove.
	(VR_INITIALIZER): Remove.
	* tree-vrp.c (value_range::set): New.
	(value_range::equiv_add): New.
	(value_range::value_range): New.
	(value_range::deep_copy): New.
	(value_range::check): New.
	(value_range::equal_p): New.
	(value_range::ignore_equivs_equal_p): New.
	(value_range::operator==): New.
	(value_range::operator!=): New.
	(value_range::symbolic_p): New.
	(value_range::numeric_p): New.
	(value_range::set_undefined): New.
	(value_range::set_varying): New.
	(value_range::may_contain_p): New.
	(value_range::equiv_clear): New.
	(value_range::singleton_p): New.
	(value_range::intersect): New.
	(value_range::dump): New.
	(value_range::set_and_canonicalize): New.
	(set_value_range): Adjust for value_range API.
	(set_value_range_to_undefined): Same.
	(set_value_range_to_varying): Same.
	(set_and_canonicalize_value_range): Same.
	(set_value_range_to_nonnull): Same.
	(set_value_range_to_null): Same.
	(range_is_null): Same.
	(range_is_nonnull): Same.
	(range_int_cst_p): Same.
	(range_int_cst_singleton_p): Same.
	(symbolic_range_p): Same.
	(range_includes_zero_p): Same.
	(value_range_constant_singleton): Same.
	(vrp_set_zero_nonzero_bits): Same.
	(ranges_from_anti_range): Same.
	(extract_range_into_wide_ints): Same.
	(extract_range_from_multiplicative_op): Same.
	(set_value_range_with_overflow): Same.
	(extract_range_from_binary_expr_1): Same.
	(extract_range_from_unary_expr): Same.
	(dump_value_range): Same.
	(debug_value_range): Same.
	(vrp_prop::check_array_ref): Same.
	(vrp_prop::check_mem_ref): Same.
	(vrp_prop::vrp_initialize): Same.
	(vrp_prop::visit_stmt): Same.
	(intersect_ranges): Same.
	(vrp_prop::visit_phi): Same.
	(vrp_prop::vrp_finalize): Same.
	(determine_value_range_1): Same.
	(determine_value_range): Same.
	(vrp_intersect_ranges_1): Rename to...
	(vrp_intersect_1): this.
	(vrp_intersect_ranges): Rename to...
	(value_range::intersect_helper): ...this.
	(vrp_meet_1): Rename to...
	(value_range::union_helper): ...this.
	(vrp_meet): Rename to...
	(value_range::union_): ...this.
	(copy_value_range): Remove.
	* tree-vrp.h (struct value_range): Rewrite into a proper class.
	(value_range::vrtype): New.
	(value_range::type): New.
	(value_range::equiv): New.
	(value_range::min): New.
	(value_range::max): New.
	(value_range::varying_p): New.
	(value_range::undefined_p): New.
	(value_range::null_p): New.
	(value_range::equiv_add): New.
	(copy_value_range): Remove.

diff --git a/gcc/bitmap.c b/gcc/bitmap.c
index d7464d78f20..538c4143cbe 100644
--- a/gcc/bitmap.c
+++ b/gcc/bitmap.c
@@ -2164,6 +2164,12 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+void
+bitmap_head::dump ()
+{
+  debug (this);
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/bitmap.h b/gcc/bitmap.h
index bdf074729df..57ae4a61086 100644
--- a/gcc/bitmap.h
+++ b/gcc/bitmap.h
@@ -243,6 +243,7 @@ struct GTY(()) bitmap_head {
   bitmap_element * GTY((skip(""))) current; /* Last element looked at.  */
   bitmap_obstack *obstack;		/* Obstack to allocate elements from.
 					   If NULL, then use GGC allocation.  */
+  void dump ();
 };
 
 /* Global data */
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 25e01e4092b..f64b3d4065b 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -3139,7 +3139,7 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
     return NULL_RTX;
 
   wide_int min, max;
-  enum value_range_type rng = get_range_info (bound, &min, &max);
+  enum value_range_kind rng = get_range_info (bound, &min, &max);
   if (rng != VR_RANGE)
     return NULL_RTX;
 
@@ -3227,7 +3227,7 @@ determine_block_size (tree len, rtx len_rtx,
   else
     {
       wide_int min, max;
-      enum value_range_type range_type = VR_UNDEFINED;
+      enum value_range_kind range_type = VR_UNDEFINED;
 
       /* Determine bounds from the type.  */
       if (tree_fits_uhwi_p (TYPE_MIN_VALUE (TREE_TYPE (len))))
@@ -3629,7 +3629,7 @@ compute_objsize (tree dest, int ostype)
 	      && INTEGRAL_TYPE_P (TREE_TYPE (off)))
 	    {
 	      wide_int min, max;
-	      enum value_range_type rng = get_range_info (off, &min, &max);
+	      enum value_range_kind rng = get_range_info (off, &min, &max);
 
 	      if (rng == VR_RANGE)
 		{
diff --git a/gcc/calls.c b/gcc/calls.c
index 80af5c3b3b3..8978d3b42fd 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1255,7 +1255,7 @@ get_size_range (tree exp, tree range[2], bool allow_zero /* = false */)
   bool integral = INTEGRAL_TYPE_P (exptype);
 
   wide_int min, max;
-  enum value_range_type range_type;
+  enum value_range_kind range_type;
 
   if (integral)
     range_type = determine_value_range (exp, &min, &max);
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 24f82d8ea4f..271cce8e20f 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -46,6 +46,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 typedef int64_t gcov_type;
 typedef uint64_t gcov_type_unsigned;
 
+struct bitmap_obstack;
 struct bitmap_head;
 typedef struct bitmap_head *bitmap;
 typedef const struct bitmap_head *const_bitmap;
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 59cedeafd71..4977eef9810 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -9255,7 +9255,7 @@ bool
 expr_not_equal_to (tree t, const wide_int &w)
 {
   wide_int min, max, nz;
-  value_range_type rtype;
+  value_range_kind rtype;
   switch (TREE_CODE (t))
     {
     case INTEGER_CST:
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fe6bc08bdd9..fd48bbf9af4 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -649,7 +649,7 @@ size_must_be_zero_p (tree size)
     return false;
 
   wide_int min, max;
-  enum value_range_type rtype = get_range_info (size, &min, &max);
+  enum value_range_kind rtype = get_range_info (size, &min, &max);
   if (rtype != VR_ANTI_RANGE)
     return false;
 
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 83e22735571..7dfec9120ab 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -2123,7 +2123,7 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
       && SSA_NAME_RANGE_INFO (node))
     {
       wide_int min, max, nonzero_bits;
-      value_range_type range_type = get_range_info (node, &min, &max);
+      value_range_kind range_type = get_range_info (node, &min, &max);
 
       if (range_type == VR_VARYING)
 	pp_printf (buffer, "# RANGE VR_VARYING");
diff --git a/gcc/gimple-ssa-evrp-analyze.c b/gcc/gimple-ssa-evrp-analyze.c
index e9afa80e191..83917f5eb0a 100644
--- a/gcc/gimple-ssa-evrp-analyze.c
+++ b/gcc/gimple-ssa-evrp-analyze.c
@@ -82,7 +82,7 @@ value_range *
 evrp_range_analyzer::try_find_new_range (tree name,
 				    tree op, tree_code code, tree limit)
 {
-  value_range vr = VR_INITIALIZER;
+  value_range vr;
   value_range *old_vr = get_value_range (name);
 
   /* Discover VR when condition is true.  */
@@ -90,11 +90,11 @@ evrp_range_analyzer::try_find_new_range (tree name,
 							 limit, &vr);
   /* If we found any usable VR, set the VR to ssa_name and create a
      PUSH old value in the stack with the old VR.  */
-  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+  if (!vr.undefined_p () && !vr.varying_p ())
     {
-      if (old_vr->type == vr.type
-	  && vrp_operand_equal_p (old_vr->min, vr.min)
-	  && vrp_operand_equal_p (old_vr->max, vr.max))
+      if (old_vr->kind () == vr.kind ()
+	  && vrp_operand_equal_p (old_vr->min (), vr.min ())
+	  && vrp_operand_equal_p (old_vr->max (), vr.max ()))
 	return NULL;
       value_range *new_vr = vr_values->allocate_value_range ();
       *new_vr = vr;
@@ -110,13 +110,10 @@ evrp_range_analyzer::set_ssa_range_info (tree lhs, value_range *vr)
   /* Set the SSA with the value range.  */
   if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
     {
-      if ((vr->type == VR_RANGE
-	   || vr->type == VR_ANTI_RANGE)
-	  && (TREE_CODE (vr->min) == INTEGER_CST)
-	  && (TREE_CODE (vr->max) == INTEGER_CST))
-	set_range_info (lhs, vr->type,
-			wi::to_wide (vr->min),
-			wi::to_wide (vr->max));
+      if (vr->constant_p ())
+	set_range_info (lhs, vr->kind (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
     }
   else if (POINTER_TYPE_P (TREE_TYPE (lhs))
 	   && range_includes_zero_p (vr) == 0)
@@ -241,7 +238,7 @@ evrp_range_analyzer::record_ranges_from_phis (basic_block bb)
       if (virtual_operand_p (lhs))
 	continue;
 
-      value_range vr_result = VR_INITIALIZER;
+      value_range vr_result;
       bool interesting = stmt_interesting_for_vrp (phi);
       if (!has_unvisited_preds && interesting)
 	vr_values->extract_range_from_phi_node (phi, &vr_result);
@@ -284,7 +281,7 @@ evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
   else if (stmt_interesting_for_vrp (stmt))
     {
       edge taken_edge;
-      value_range vr = VR_INITIALIZER;
+      value_range vr;
       vr_values->extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
       if (output)
 	{
@@ -315,7 +312,7 @@ evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
 		 bitmaps.  Ugh.  */
 	      value_range *new_vr = vr_values->allocate_value_range ();
 	      *new_vr = vr;
-	      new_vr->equiv = NULL;
+	      new_vr->equiv_clear ();
 	      push_value_range (output, new_vr);
 	    }
 	}
diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 50e8adc1aad..b075c1051d8 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -161,8 +161,7 @@ evrp_dom_walker::before_dom_children (basic_block bb)
 	      value_range *vr = evrp_range_analyzer.get_value_range (output);
 
 	      /* Mark stmts whose output we fully propagate for removal.  */
-	      if ((vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
-		  && (val = value_range_constant_singleton (vr))
+	      if ((val = value_range_constant_singleton (vr))
 		  && may_propagate_copy (output, val)
 		  && !stmt_could_throw_p (stmt)
 		  && !gimple_has_side_effects (stmt))
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index 471bfc45eb8..90f028d50bd 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -1052,9 +1052,7 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 	{
 	  /* Try to determine the range of values of the integer argument.  */
 	  value_range *vr = vr_values->get_value_range (arg);
-	  if (vr->type == VR_RANGE
-	      && TREE_CODE (vr->min) == INTEGER_CST
-	      && TREE_CODE (vr->max) == INTEGER_CST)
+	  if (range_int_cst_p (vr))
 	    {
 	      HOST_WIDE_INT type_min
 		= (TYPE_UNSIGNED (argtype)
@@ -1063,8 +1061,8 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 
 	      HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype));
 
-	      *pmin = TREE_INT_CST_LOW (vr->min);
-	      *pmax = TREE_INT_CST_LOW (vr->max);
+	      *pmin = TREE_INT_CST_LOW (vr->min ());
+	      *pmax = TREE_INT_CST_LOW (vr->max ());
 
 	      if (*pmin < *pmax)
 		{
@@ -1354,12 +1352,10 @@ format_integer (const directive &dir, tree arg, vr_values *vr_values)
       /* Try to determine the range of values of the integer argument
 	 (range information is not available for pointers).  */
       value_range *vr = vr_values->get_value_range (arg);
-      if (vr->type == VR_RANGE
-	  && TREE_CODE (vr->min) == INTEGER_CST
-	  && TREE_CODE (vr->max) == INTEGER_CST)
+      if (range_int_cst_p (vr))
 	{
-	  argmin = vr->min;
-	  argmax = vr->max;
+	  argmin = vr->min ();
+	  argmax = vr->max ();
 
 	  /* Set KNOWNRANGE if the argument is in a known subrange
 	     of the directive's type and neither width nor precision
@@ -1372,12 +1368,11 @@ format_integer (const directive &dir, tree arg, vr_values *vr_values)
 	  res.argmin = argmin;
 	  res.argmax = argmax;
 	}
-      else if (vr->type == VR_ANTI_RANGE)
+      else if (vr->kind () == VR_ANTI_RANGE)
 	{
 	  /* Handle anti-ranges if/when bug 71690 is resolved.  */
 	}
-      else if (vr->type == VR_VARYING
-	       || vr->type == VR_UNDEFINED)
+      else if (vr->varying_p () || vr->undefined_p ())
 	{
 	  /* The argument here may be the result of promoting the actual
 	     argument to int.  Try to determine the type of the actual
@@ -3903,12 +3898,10 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi)
 	     and use the greater of the two at level 1 and the smaller
 	     of them at level 2.  */
 	  value_range *vr = evrp_range_analyzer.get_value_range (size);
-	  if (vr->type == VR_RANGE
-	      && TREE_CODE (vr->min) == INTEGER_CST
-	      && TREE_CODE (vr->max) == INTEGER_CST)
+	  if (range_int_cst_p (vr))
 	    dstsize = (warn_level < 2
-		       ? TREE_INT_CST_LOW (vr->max)
-		       : TREE_INT_CST_LOW (vr->min));
+		       ? TREE_INT_CST_LOW (vr->max ())
+		       : TREE_INT_CST_LOW (vr->min ()));
 
 	  /* The destination size is not constant.  If the function is
 	     bounded (e.g., snprintf) a lower bound of zero doesn't
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
index d1b1de4a2d5..9d2d68ad54b 100644
--- a/gcc/gimple-ssa-warn-alloca.c
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -272,7 +272,7 @@ alloca_call_type_by_arg (tree arg, tree arg_casted, edge e,
       && TREE_CODE (limit) == SSA_NAME)
     {
       wide_int min, max;
-      value_range_type range_type = get_range_info (limit, &min, &max);
+      value_range_kind range_type = get_range_info (limit, &min, &max);
 
       if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
 	return alloca_type_and_limit (ALLOCA_BOUND_UNKNOWN);
@@ -364,7 +364,7 @@ alloca_call_type (gimple *stmt, bool is_vla, tree *invalid_casted_type)
   // Check the range info if available.
   if (TREE_CODE (len) == SSA_NAME)
     {
-      value_range_type range_type = get_range_info (len, &min, &max);
+      value_range_kind range_type = get_range_info (len, &min, &max);
       if (range_type == VR_RANGE)
 	{
 	  if (wi::leu_p (max, max_size))
diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index ea30b7108f8..e3cbf42f2d9 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -312,7 +312,7 @@ builtin_memref::extend_offset_range (tree offset)
   if (TREE_CODE (offset) == SSA_NAME)
     {
       wide_int min, max;
-      value_range_type rng = get_range_info (offset, &min, &max);
+      value_range_kind rng = get_range_info (offset, &min, &max);
       if (rng == VR_RANGE)
 	{
 	  offrange[0] += offset_int::from (min, SIGNED);
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 27ae8e0fe27..4471bae11c7 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -314,7 +314,7 @@ public:
   inline bool set_to_bottom ();
   bool meet_with (const value_range *p_vr);
   bool meet_with (const ipcp_vr_lattice &other);
-  void init () { m_vr.type = VR_UNDEFINED; }
+  void init () { gcc_assert (m_vr.undefined_p ()); }
   void print (FILE * f);
 
 private:
@@ -914,28 +914,21 @@ ipcp_vr_lattice::meet_with (const value_range *p_vr)
   return meet_with_1 (p_vr);
 }
 
-/* Meet the current value of the lattice with value ranfge described by
-   OTHER_VR lattice.  */
+/* Meet the current value of the lattice with value range described by
+   OTHER_VR lattice.  Return TRUE if anything changed.  */
 
 bool
 ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
 {
-  tree min = m_vr.min, max = m_vr.max;
-  value_range_type type = m_vr.type;
-
   if (bottom_p ())
     return false;
 
-  if (other_vr->type == VR_VARYING)
+  if (other_vr->varying_p ())
     return set_to_bottom ();
 
-  vrp_meet (&m_vr, other_vr);
-  if (type != m_vr.type
-      || min != m_vr.min
-      || max != m_vr.max)
-    return true;
-  else
-    return false;
+  value_range save (m_vr);
+  m_vr.union_ (other_vr);
+  return !m_vr.ignore_equivs_equal_p (save);
 }
 
 /* Return true if value range information in the lattice is yet unknown.  */
@@ -943,7 +936,7 @@ ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
 bool
 ipcp_vr_lattice::top_p () const
 {
-  return m_vr.type == VR_UNDEFINED;
+  return m_vr.undefined_p ();
 }
 
 /* Return true if value range information in the lattice is known to be
@@ -952,7 +945,7 @@ ipcp_vr_lattice::top_p () const
 bool
 ipcp_vr_lattice::bottom_p () const
 {
-  return m_vr.type == VR_VARYING;
+  return m_vr.varying_p ();
 }
 
 /* Set value range information in the lattice to bottom.  Return true if it
@@ -961,9 +954,9 @@ ipcp_vr_lattice::bottom_p () const
 bool
 ipcp_vr_lattice::set_to_bottom ()
 {
-  if (m_vr.type == VR_VARYING)
+  if (m_vr.varying_p ())
     return false;
-  m_vr.type = VR_VARYING;
+  m_vr.set_varying ();
   return true;
 }
 
@@ -1882,12 +1875,11 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr, value_range *src_vr,
 				   enum tree_code operation,
 				   tree dst_type, tree src_type)
 {
-  memset (dst_vr, 0, sizeof (*dst_vr));
+  *dst_vr = value_range ();
   extract_range_from_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
-  if (dst_vr->type == VR_RANGE || dst_vr->type == VR_ANTI_RANGE)
-    return true;
-  else
+  if (dst_vr->varying_p () || dst_vr->undefined_p ())
     return false;
+  return true;
 }
 
 /* Propagate value range across jump function JFUNC that is associated with
@@ -1940,11 +1932,7 @@ 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;
-	  memset (&tmpvr, 0, sizeof (tmpvr));
-	  tmpvr.type = VR_RANGE;
-	  tmpvr.min = val;
-	  tmpvr.max = val;
+	  value_range tmpvr (VR_RANGE, val, val);
 	  return dest_lat->meet_with (&tmpvr);
 	}
     }
@@ -1953,7 +1941,7 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
   if (jfunc->m_vr
       && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
 					    param_type,
-					    TREE_TYPE (jfunc->m_vr->min)))
+					    jfunc->m_vr->type ()))
     return dest_lat->meet_with (&vr);
   else
     return dest_lat->set_to_bottom ();
@@ -5028,9 +5016,9 @@ ipcp_store_vr_results (void)
 	      && !plats->m_value_range.top_p ())
 	    {
 	      vr.known = true;
-	      vr.type = plats->m_value_range.m_vr.type;
-	      vr.min = wi::to_wide (plats->m_value_range.m_vr.min);
-	      vr.max = wi::to_wide (plats->m_value_range.m_vr.max);
+	      vr.type = plats->m_value_range.m_vr.kind ();
+	      vr.min = wi::to_wide (plats->m_value_range.m_vr.min ());
+	      vr.max = wi::to_wide (plats->m_value_range.m_vr.max ());
 	    }
 	  else
 	    {
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 8b19fe3f391..1e40997c92c 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -113,16 +113,16 @@ struct ipa_vr_ggc_hash_traits : public ggc_cache_remove <value_range *>
   static hashval_t
   hash (const value_range *p)
     {
-      gcc_checking_assert (!p->equiv);
-      inchash::hash hstate (p->type);
-      hstate.add_ptr (p->min);
-      hstate.add_ptr (p->max);
+      gcc_checking_assert (!p->equiv ());
+      inchash::hash hstate (p->kind ());
+      hstate.add_ptr (p->min ());
+      hstate.add_ptr (p->max ());
       return hstate.end ();
     }
   static bool
   equal (const value_range *a, const value_range *b)
     {
-      return a->type == b->type && a->min == b->min && a->max == b->max;
+      return a->ignore_equivs_equal_p (*b);
     }
   static void
   mark_empty (value_range *&p)
@@ -398,10 +398,10 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
 	{
 	  fprintf (f, "         VR  ");
 	  fprintf (f, "%s[",
-		   (jump_func->m_vr->type == VR_ANTI_RANGE) ? "~" : "");
-	  print_decs (wi::to_wide (jump_func->m_vr->min), f);
+		   (jump_func->m_vr->kind () == VR_ANTI_RANGE) ? "~" : "");
+	  print_decs (wi::to_wide (jump_func->m_vr->min ()), f);
 	  fprintf (f, ", ");
-	  print_decs (wi::to_wide (jump_func->m_vr->max), f);
+	  print_decs (wi::to_wide (jump_func->m_vr->max ()), f);
 	  fprintf (f, "]\n");
 	}
       else
@@ -1789,13 +1789,9 @@ ipa_get_value_range (value_range *tmp)
    value_ranges.  */
 
 static value_range *
-ipa_get_value_range (enum value_range_type type, tree min, tree max)
+ipa_get_value_range (enum value_range_kind type, tree min, tree max)
 {
-  value_range tmp;
-  tmp.type = type;
-  tmp.min = min;
-  tmp.max = max;
-  tmp.equiv = NULL;
+  value_range tmp (type, min, max);
   return ipa_get_value_range (&tmp);
 }
 
@@ -1804,7 +1800,7 @@ ipa_get_value_range (enum value_range_type type, tree min, tree max)
    same value_range structures.  */
 
 static void
-ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_type type,
+ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_kind type,
 		  tree min, tree max)
 {
   jf->m_vr = ipa_get_value_range (type, min, max);
@@ -1884,22 +1880,19 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
       else
 	{
 	  wide_int min, max;
-	  value_range_type type;
+	  value_range_kind type;
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
 	      && (type = get_range_info (arg, &min, &max))
 	      && (type == VR_RANGE || type == VR_ANTI_RANGE))
 	    {
-	      value_range tmpvr,resvr;
-
-	      tmpvr.type = type;
-	      tmpvr.min = wide_int_to_tree (TREE_TYPE (arg), min);
-	      tmpvr.max = wide_int_to_tree (TREE_TYPE (arg), max);
-	      tmpvr.equiv = NULL;
-	      memset (&resvr, 0, sizeof (resvr));
+	      value_range resvr;
+	      value_range tmpvr (type,
+				 wide_int_to_tree (TREE_TYPE (arg), min),
+				 wide_int_to_tree (TREE_TYPE (arg), max));
 	      extract_range_from_unary_expr (&resvr, NOP_EXPR, param_type,
 					     &tmpvr, TREE_TYPE (arg));
-	      if (resvr.type == VR_RANGE || resvr.type == VR_ANTI_RANGE)
+	      if (!resvr.undefined_p () && !resvr.varying_p ())
 		ipa_set_jfunc_vr (jfunc, &resvr);
 	      else
 		gcc_assert (!jfunc->m_vr);
@@ -4126,9 +4119,9 @@ ipa_write_jump_function (struct output_block *ob,
   if (jump_func->m_vr)
     {
       streamer_write_enum (ob->main_stream, value_rang_type,
-			   VR_LAST, jump_func->m_vr->type);
-      stream_write_tree (ob, jump_func->m_vr->min, true);
-      stream_write_tree (ob, jump_func->m_vr->max, true);
+			   VR_LAST, jump_func->m_vr->kind ());
+      stream_write_tree (ob, jump_func->m_vr->min (), true);
+      stream_write_tree (ob, jump_func->m_vr->max (), true);
     }
 }
 
@@ -4216,7 +4209,7 @@ ipa_read_jump_function (struct lto_input_block *ib,
   bool vr_known = bp_unpack_value (&vr_bp, 1);
   if (vr_known)
     {
-      enum value_range_type type = streamer_read_enum (ib, value_range_type,
+      enum value_range_kind type = streamer_read_enum (ib, value_range_kind,
 						       VR_LAST);
       tree min = stream_read_tree (ib, data_in);
       tree max = stream_read_tree (ib, data_in);
@@ -4647,7 +4640,7 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
 	  parm_vr->known = bp_unpack_value (&bp, 1);
 	  if (parm_vr->known)
 	    {
-	      parm_vr->type = streamer_read_enum (ib, value_range_type,
+	      parm_vr->type = streamer_read_enum (ib, value_range_kind,
 						  VR_LAST);
 	      parm_vr->min = streamer_read_wide_int (ib);
 	      parm_vr->max = streamer_read_wide_int (ib);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 55e10cf0f27..8a53bb89f3f 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -160,7 +160,7 @@ struct GTY(()) ipa_vr
 {
   /* The data fields below are valid only if known is true.  */
   bool known;
-  enum value_range_type type;
+  enum value_range_kind type;
   wide_int min;
   wide_int max;
 };
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index 69c5f7b28ae..66e780d635a 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -721,7 +721,7 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
 		if (TREE_CODE (tmp_var) != SSA_NAME)
 		  return false;
 		wide_int var_min, var_max;
-		value_range_type vr_type = get_range_info (tmp_var, &var_min,
+		value_range_kind vr_type = get_range_info (tmp_var, &var_min,
 							   &var_max);
 		wide_int var_nonzero = get_nonzero_bits (tmp_var);
 		signop sgn = TYPE_SIGN (itype);
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index f7cc034b26e..c50618dc809 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -882,25 +882,27 @@ simplify_stmt_for_jump_threading (gimple *stmt,
 	return NULL_TREE;
 
       value_range *vr = x_vr_values->get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  size_t i, j;
 
-	  find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+	  find_case_label_range (switch_stmt, vr->min (), vr->max (), &i, &j);
 
 	  if (i == j)
 	    {
 	      tree label = gimple_switch_label (switch_stmt, i);
+	      tree singleton;
 
 	      if (CASE_HIGH (label) != NULL_TREE
-		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
-		     && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
-		  : (tree_int_cst_equal (CASE_LOW (label), vr->min)
-		     && tree_int_cst_equal (vr->min, vr->max)))
+		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min ()) <= 0
+		     && tree_int_cst_compare (CASE_HIGH (label), vr->max ()) >= 0)
+		  : (vr->singleton_p (&singleton)
+		     && tree_int_cst_equal (CASE_LOW (label), singleton)))
 		return label;
 
 	      if (i > j)
@@ -908,7 +910,7 @@ simplify_stmt_for_jump_threading (gimple *stmt,
 	    }
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->kind () == VR_ANTI_RANGE)
           {
             unsigned n = gimple_switch_num_labels (switch_stmt);
             tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -917,10 +919,10 @@ simplify_stmt_for_jump_threading (gimple *stmt,
             /* The default label will be taken only if the anti-range of the
                operand is entirely outside the bounds of all the (non-default)
                case labels.  */
-            if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+            if (tree_int_cst_compare (vr->min (), CASE_LOW (min_label)) <= 0
                 && (CASE_HIGH (max_label) != NULL_TREE
-                    ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
-                    : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+                    ? tree_int_cst_compare (vr->max (), CASE_HIGH (max_label)) >= 0
+                    : tree_int_cst_compare (vr->max (), CASE_LOW (max_label)) >= 0))
             return gimple_switch_label (switch_stmt, 0);
           }
 	return NULL_TREE;
@@ -936,11 +938,12 @@ simplify_stmt_for_jump_threading (gimple *stmt,
 	{
 	  edge dummy_e;
 	  tree dummy_tree;
-	  value_range new_vr = VR_INITIALIZER;
+	  value_range new_vr;
 	  x_vr_values->extract_range_from_stmt (stmt, &dummy_e,
 					      &dummy_tree, &new_vr);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  tree singleton;
+	  if (new_vr.singleton_p (&singleton))
+	    return singleton;
 	}
     }
   return NULL;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 7b6c91ca6da..e2bc936ed52 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -353,7 +353,7 @@ determine_value_range (struct loop *loop, tree type, tree var, mpz_t off,
   mpz_t minm, maxm;
   basic_block bb;
   wide_int minv, maxv;
-  enum value_range_type rtype = VR_VARYING;
+  enum value_range_kind rtype = VR_VARYING;
 
   /* If the expression is a constant, we know its value exactly.  */
   if (integer_zerop (var))
@@ -4673,7 +4673,7 @@ scev_var_range_cant_overflow (tree var, tree step, struct loop *loop)
 {
   tree type;
   wide_int minv, maxv, diff, step_wi;
-  enum value_range_type rtype;
+  enum value_range_kind rtype;
 
   if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
     return false;
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 3fa5ef56f38..2db2823553b 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -1200,7 +1200,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
       else if (TREE_CODE (bound) == SSA_NAME)
 	{
 	  wide_int minbound, maxbound;
-	  value_range_type rng = get_range_info (bound, &minbound, &maxbound);
+	  value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
 	  if (rng == VR_RANGE)
 	    {
 	      /* For a bound in a known range, adjust the range determined
@@ -1856,7 +1856,7 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
     cntrange[0] = cntrange[1] = wi::to_wide (cnt);
   else if (TREE_CODE (cnt) == SSA_NAME)
     {
-      enum value_range_type rng = get_range_info (cnt, cntrange, cntrange + 1);
+      enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
       if (rng == VR_RANGE)
 	;
       else if (rng == VR_ANTI_RANGE)
@@ -3682,7 +3682,7 @@ strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh)
 			   if we don't have anything better.  */
 			wide_int min, max;
 			tree type = TREE_TYPE (lhs);
-			enum value_range_type vr
+			enum value_range_kind vr
 			  = get_range_info (lhs, &min, &max);
 			if (vr == VR_VARYING
 			    || (vr == VR_RANGE
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index a2304493495..0b1f9733fdd 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -166,7 +166,7 @@ record_temporary_equivalences_from_phis (edge e,
 	     away in the VR stack.  */
 	  vr_values *vr_values = evrp_range_analyzer->get_vr_values ();
 	  value_range *new_vr = vr_values->allocate_value_range ();
-	  memset (new_vr, 0, sizeof (value_range));
+	  *new_vr = value_range ();
 
 	  /* There are three cases to consider:
 
@@ -179,7 +179,7 @@ record_temporary_equivalences_from_phis (edge e,
 	       Otherwise set NEW_VR to varying.  This may be overly
 	       conservative.  */
 	  if (TREE_CODE (src) == SSA_NAME)
-	    copy_value_range (new_vr, vr_values->get_value_range (src));
+	    new_vr->deep_copy (vr_values->get_value_range (src));
 	  else if (TREE_CODE (src) == INTEGER_CST)
 	    set_value_range_to_value (new_vr, src,  NULL);
 	  else
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 6cce43be593..66b2941fbf5 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -331,7 +331,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
    NAME.  */
 
 void
-set_range_info_raw (tree name, enum value_range_type range_type,
+set_range_info_raw (tree name, enum value_range_kind range_type,
 		    const wide_int_ref &min, const wide_int_ref &max)
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
@@ -372,7 +372,7 @@ set_range_info_raw (tree name, enum value_range_type range_type,
    NAME while making sure we don't store useless range info.  */
 
 void
-set_range_info (tree name, enum value_range_type range_type,
+set_range_info (tree name, enum value_range_kind range_type,
 		const wide_int_ref &min, const wide_int_ref &max)
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
@@ -397,11 +397,11 @@ set_range_info (tree name, enum value_range_type range_type,
 }
 
 
-/* Gets range information MIN, MAX and returns enum value_range_type
-   corresponding to tree ssa_name NAME.  enum value_range_type returned
+/* Gets range information MIN, MAX and returns enum value_range_kind
+   corresponding to tree ssa_name NAME.  enum value_range_kind returned
    is used to determine if MIN and MAX are valid values.  */
 
-enum value_range_type
+enum value_range_kind
 get_range_info (const_tree name, wide_int *min, wide_int *max)
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
@@ -727,7 +727,7 @@ duplicate_ssa_name_ptr_info (tree name, struct ptr_info_def *ptr_info)
 /* Creates a duplicate of the range_info_def at RANGE_INFO of type
    RANGE_TYPE for use by the SSA name NAME.  */
 void
-duplicate_ssa_name_range_info (tree name, enum value_range_type range_type,
+duplicate_ssa_name_range_info (tree name, enum value_range_kind range_type,
 			       struct range_info_def *range_info)
 {
   struct range_info_def *new_range_info;
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index d39f3969436..18a001a5461 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -67,13 +67,13 @@ struct GTY ((variable_size)) range_info_def {
     if (VAR)
 
 /* Sets the value range to SSA.  */
-extern void set_range_info (tree, enum value_range_type, const wide_int_ref &,
+extern void set_range_info (tree, enum value_range_kind, const wide_int_ref &,
 			    const wide_int_ref &);
-extern void set_range_info_raw (tree, enum value_range_type,
+extern void set_range_info_raw (tree, enum value_range_kind,
 				const wide_int_ref &,
 				const wide_int_ref &);
 /* Gets the value range from SSA.  */
-extern enum value_range_type get_range_info (const_tree, wide_int *,
+extern enum value_range_kind get_range_info (const_tree, wide_int *,
 					     wide_int *);
 extern void set_nonzero_bits (tree, const wide_int_ref &);
 extern wide_int get_nonzero_bits (const_tree);
@@ -97,7 +97,7 @@ extern bool get_ptr_nonnull (const_tree);
 extern tree copy_ssa_name_fn (struct function *, tree, gimple *);
 extern void duplicate_ssa_name_ptr_info (tree, struct ptr_info_def *);
 extern tree duplicate_ssa_name_fn (struct function *, tree, gimple *);
-extern void duplicate_ssa_name_range_info (tree, enum value_range_type,
+extern void duplicate_ssa_name_range_info (tree, enum value_range_kind,
 					   struct range_info_def *);
 extern void reset_flow_sensitive_info (tree);
 extern void reset_flow_sensitive_info_in_bb (basic_block);
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 7956c1326d3..2be94566270 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -53,7 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 static bool
 vect_get_range_info (tree var, wide_int *min_value, wide_int *max_value)
 {
-  value_range_type vr_type = get_range_info (var, min_value, max_value);
+  value_range_kind vr_type = get_range_info (var, min_value, max_value);
   wide_int nonzero = get_nonzero_bits (var);
   signop sgn = TYPE_SIGN (TREE_TYPE (var));
   if (intersect_range_with_nonzero_bits (vr_type, min_value, max_value,
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index cbc2ea2f26b..0ddc940880b 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -73,6 +73,303 @@ along with GCC; see the file COPYING3.  If not see
    for still active basic-blocks.  */
 static sbitmap *live;
 
+/* Initialize value_range.  */
+
+void
+value_range::set (enum value_range_kind kind, tree min, tree max,
+		  bitmap equiv)
+{
+  m_kind = kind;
+  m_min = min;
+  m_max = max;
+
+  /* Since updating the equivalence set involves deep copying the
+     bitmaps, only do it if absolutely necessary.
+
+     All equivalence bitmaps are allocated from the same obstack.  So
+     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
+  if (m_equiv == NULL
+      && equiv != NULL)
+    m_equiv = BITMAP_ALLOC (equiv->obstack);
+
+  if (equiv != m_equiv)
+    {
+      if (equiv && !bitmap_empty_p (equiv))
+	bitmap_copy (m_equiv, equiv);
+      else
+	bitmap_clear (m_equiv);
+    }
+  if (flag_checking)
+    check ();
+}
+
+value_range::value_range (value_range_kind kind, tree min, tree max,
+			  bitmap equiv)
+{
+  m_equiv = NULL;
+  set (kind, min, max, equiv);
+}
+
+/* Like above, but keep the equivalences intact.  */
+
+void
+value_range::update (value_range_kind kind, tree min, tree max)
+{
+  set (kind, min, max, m_equiv);
+}
+
+/* Copy value_range in FROM into THIS while avoiding bitmap sharing.
+
+   Note: The code that avoids the bitmap sharing looks at the existing
+   this->m_equiv, so this function cannot be used to initalize an
+   object.  Use the constructors for initialization.  */
+
+void
+value_range::deep_copy (const value_range *from)
+{
+  set (from->m_kind, from->m_min, from->m_max, from->m_equiv);
+}
+
+/* Check the validity of the range.  */
+
+void
+value_range::check ()
+{
+  switch (m_kind)
+    {
+    case VR_RANGE:
+    case VR_ANTI_RANGE:
+      {
+	int cmp;
+
+	gcc_assert (m_min && m_max);
+
+	gcc_assert (!TREE_OVERFLOW_P (m_min) && !TREE_OVERFLOW_P (m_max));
+
+	/* Creating ~[-MIN, +MAX] is stupid because that would be
+	   the empty set.  */
+	if (INTEGRAL_TYPE_P (TREE_TYPE (m_min)) && m_kind == VR_ANTI_RANGE)
+	  gcc_assert (!vrp_val_is_min (m_min) || !vrp_val_is_max (m_max));
+
+	cmp = compare_values (m_min, m_max);
+	gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
+	break;
+      }
+    case VR_UNDEFINED:
+    case VR_VARYING:
+      gcc_assert (!m_min && !m_max);
+      gcc_assert (!m_equiv || bitmap_empty_p (m_equiv));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Returns TRUE if THIS == OTHER.  Ignores the equivalence bitmap if
+   IGNORE_EQUIVS is TRUE.  */
+
+bool
+value_range::equal_p (const value_range &other, bool ignore_equivs) const
+{
+ return (m_kind == other.m_kind
+	 && vrp_operand_equal_p (m_min, other.m_min)
+	 && vrp_operand_equal_p (m_max, other.m_max)
+	 && (ignore_equivs
+	     || vrp_bitmap_equal_p (m_equiv, other.m_equiv)));
+}
+
+/* Return equality while ignoring equivalence bitmap.  */
+
+bool
+value_range::ignore_equivs_equal_p (const value_range &other) const
+{
+  return equal_p (other, /*ignore_equivs=*/true);
+}
+
+bool
+value_range::operator== (const value_range &other) const
+{
+ return equal_p (other, /*ignore_equivs=*/false);
+}
+
+bool
+value_range::operator!= (const value_range &other) const
+{
+ return !(*this == other);
+}
+
+/* Return TRUE if this is a symbolic range.  */
+
+bool
+value_range::symbolic_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && (!is_gimple_min_invariant (m_min)
+	      || !is_gimple_min_invariant (m_max)));
+}
+
+/* NOTE: This is not the inverse of symbolic_p because the range
+   could also be varying or undefined.  Ideally they should be inverse
+   of each other, with varying only applying to symbolics.  Varying of
+   constants would be represented as [-MIN, +MAX].  */
+
+bool
+value_range::constant_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && TREE_CODE (m_min) == INTEGER_CST
+	  && TREE_CODE (m_max) == INTEGER_CST);
+}
+
+void
+value_range::set_undefined ()
+{
+ equiv_clear ();
+  *this = value_range (VR_UNDEFINED, NULL, NULL, NULL);
+}
+
+void
+value_range::set_varying ()
+{
+  equiv_clear ();
+  *this = value_range (VR_VARYING, NULL, NULL, NULL);
+}
+
+/* Return TRUE if it is possible that range contains VAL.  */
+
+bool
+value_range::may_contain_p (tree val) const
+{
+  if (varying_p ())
+    return true;
+
+  if (undefined_p ())
+    return true;
+
+  if (m_kind == VR_ANTI_RANGE)
+    {
+      int res = value_inside_range (val, m_min, m_max);
+      return res == 0 || res == -2;
+    }
+  return value_inside_range (val, m_min, m_max) != 0;
+}
+
+void
+value_range::equiv_clear ()
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+}
+
+/* Add VAR and VAR's equivalence set (VAR_VR) to the equivalence
+   bitmap.  If no equivalence table has been created, OBSTACK is the
+   obstack to use (NULL for the default obstack).
+
+   This is the central point where equivalence processing can be
+   turned on/off.  */
+
+void
+value_range::equiv_add (const_tree var,
+			const value_range *var_vr,
+			bitmap_obstack *obstack)
+{
+  if (!m_equiv)
+    m_equiv = BITMAP_ALLOC (obstack);
+  unsigned ver = SSA_NAME_VERSION (var);
+  bitmap_set_bit (m_equiv, ver);
+  if (var_vr && var_vr->m_equiv)
+    bitmap_ior_into (m_equiv, var_vr->m_equiv);
+}
+
+/* If range is a singleton, place it in RESULT and return TRUE.
+   Note: A singleton can be any gimple invariant, not just constants.
+   So, [&x, &x] counts as a singleton.  */
+
+bool
+value_range::singleton_p (tree *result) const
+{
+  if (m_kind == VR_RANGE
+      && vrp_operand_equal_p (m_min, m_max)
+      && is_gimple_min_invariant (m_min))
+    {
+      if (result)
+        *result = m_min;
+      return true;
+    }
+  return false;
+}
+
+tree
+value_range::type () const
+{
+ /* Types are only valid for VR_RANGE and VR_ANTI_RANGE, which are
+    known to have non-zero min/max.  */
+ gcc_assert (m_min);
+ return TREE_TYPE (m_min);
+}
+
+/* Dump value range to FILE.  */
+
+void
+value_range::dump (FILE *file) const
+{
+  if (undefined_p ())
+    fprintf (file, "UNDEFINED");
+  else if (m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
+    {
+      tree type = TREE_TYPE (m_min);
+
+      fprintf (file, "%s[", (m_kind == VR_ANTI_RANGE) ? "~" : "");
+
+      if (INTEGRAL_TYPE_P (type)
+	  && !TYPE_UNSIGNED (type)
+	  && vrp_val_is_min (m_min))
+	fprintf (file, "-INF");
+      else
+	print_generic_expr (file, m_min);
+
+      fprintf (file, ", ");
+
+      if (INTEGRAL_TYPE_P (type)
+	  && vrp_val_is_max (m_max))
+	fprintf (file, "+INF");
+      else
+	print_generic_expr (file, m_max);
+
+      fprintf (file, "]");
+
+      if (m_equiv)
+	{
+	  bitmap_iterator bi;
+	  unsigned i, c = 0;
+
+	  fprintf (file, "  EQUIVALENCES: { ");
+
+	  EXECUTE_IF_SET_IN_BITMAP (m_equiv, 0, i, bi)
+	    {
+	      print_generic_expr (file, ssa_name (i));
+	      fprintf (file, " ");
+	      c++;
+	    }
+
+	  fprintf (file, "} (%u elements)", c);
+	}
+    }
+  else if (varying_p ())
+    fprintf (file, "VARYING");
+  else
+    fprintf (file, "INVALID RANGE");
+}
+
+void
+value_range::dump () const
+{
+  dump_value_range (stderr, this);
+  fprintf (stderr, "\n");
+}
+
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 static bool
@@ -175,8 +472,8 @@ vrp_val_is_min (const_tree val)
 
    SGN gives the sign of the values described by the range.  */
 
-enum value_range_type
-intersect_range_with_nonzero_bits (enum value_range_type vr_type,
+enum value_range_kind
+intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
 				   wide_int *min, wide_int *max,
 				   const wide_int &nonzero_bits,
 				   signop sgn)
@@ -245,10 +542,7 @@ intersect_range_with_nonzero_bits (enum value_range_type vr_type,
 static inline void
 set_value_range_to_undefined (value_range *vr)
 {
-  vr->type = VR_UNDEFINED;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_undefined ();
 }
 
 /* Set value range VR to VR_VARYING.  */
@@ -256,67 +550,21 @@ set_value_range_to_undefined (value_range *vr)
 void
 set_value_range_to_varying (value_range *vr)
 {
-  vr->type = VR_VARYING;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_varying ();
 }
 
 /* Set value range VR to {T, MIN, MAX, EQUIV}.  */
 
 void
-set_value_range (value_range *vr, enum value_range_type t, tree min,
-		 tree max, bitmap equiv)
+set_value_range (value_range *vr, enum value_range_kind kind,
+		 tree min, tree max, bitmap equiv)
 {
-  /* Check the validity of the range.  */
-  if (flag_checking
-      && (t == VR_RANGE || t == VR_ANTI_RANGE))
-    {
-      int cmp;
-
-      gcc_assert (min && max);
-
-      gcc_assert (!TREE_OVERFLOW_P (min) && !TREE_OVERFLOW_P (max));
-
-      if (INTEGRAL_TYPE_P (TREE_TYPE (min)) && t == VR_ANTI_RANGE)
-	gcc_assert (!vrp_val_is_min (min) || !vrp_val_is_max (max));
-
-      cmp = compare_values (min, max);
-      gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
-    }
-
-  if (flag_checking
-      && (t == VR_UNDEFINED || t == VR_VARYING))
-    {
-      gcc_assert (min == NULL_TREE && max == NULL_TREE);
-      gcc_assert (equiv == NULL || bitmap_empty_p (equiv));
-    }
-
-  vr->type = t;
-  vr->min = min;
-  vr->max = max;
-
-  /* Since updating the equivalence set involves deep copying the
-     bitmaps, only do it if absolutely necessary.
-
-     All equivalence bitmaps are allocated from the same obstack.  So
-     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
-  if (vr->equiv == NULL
-      && equiv != NULL)
-    vr->equiv = BITMAP_ALLOC (equiv->obstack);
-
-  if (equiv != vr->equiv)
-    {
-      if (equiv && !bitmap_empty_p (equiv))
-	bitmap_copy (vr->equiv, equiv);
-      else
-	bitmap_clear (vr->equiv);
-    }
+  *vr = value_range (kind, min, max, equiv);
 }
 
 
-/* Set value range VR to the canonical form of {T, MIN, MAX, EQUIV}.
-   This means adjusting T, MIN and MAX representing the case of a
+/* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
+   This means adjusting VRTYPE, MIN and MAX representing the case of a
    wrapping range with MAX < MIN covering [MIN, type_max] U [type_min, MAX]
    as anti-rage ~[MAX+1, MIN-1].  Likewise for wrapping anti-ranges.
    In corner cases where MAX+1 or MIN-1 wraps this will fall back
@@ -325,18 +573,18 @@ set_value_range (value_range *vr, enum value_range_type t, tree min,
    extract ranges from var + CST op limit.  */
 
 void
-set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
-				  tree min, tree max, bitmap equiv)
+value_range::set_and_canonicalize (enum value_range_kind kind,
+				   tree min, tree max, bitmap equiv)
 {
   /* Use the canonical setters for VR_UNDEFINED and VR_VARYING.  */
-  if (t == VR_UNDEFINED)
+  if (kind == VR_UNDEFINED)
     {
-      set_value_range_to_undefined (vr);
+      set_undefined ();
       return;
     }
-  else if (t == VR_VARYING)
+  else if (kind == VR_VARYING)
     {
-      set_value_range_to_varying (vr);
+      set_varying ();
       return;
     }
 
@@ -344,7 +592,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
   if (TREE_CODE (min) != INTEGER_CST
       || TREE_CODE (max) != INTEGER_CST)
     {
-      set_value_range (vr, t, min, max, equiv);
+      set_value_range (this, kind, min, max, equiv);
       return;
     }
 
@@ -359,7 +607,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	 for VR_ANTI_RANGE empty range, so drop to varying as well.  */
       if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
 	{
-	  set_value_range_to_varying (vr);
+	  set_varying ();
 	  return;
 	}
 
@@ -373,15 +621,15 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	 to varying in this case.  */
       if (tree_int_cst_lt (max, min))
 	{
-	  set_value_range_to_varying (vr);
+	  set_varying ();
 	  return;
 	}
 
-      t = t == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
+      kind = kind == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
     }
 
   /* Anti-ranges that can be represented as ranges should be so.  */
-  if (t == VR_ANTI_RANGE)
+  if (kind == VR_ANTI_RANGE)
     {
       /* For -fstrict-enums we may receive out-of-range ranges so consider
          values < -INF and values > INF as -INF/INF as well.  */
@@ -395,7 +643,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	{
 	  /* We cannot deal with empty ranges, drop to varying.
 	     ???  This could be VR_UNDEFINED instead.  */
-	  set_value_range_to_varying (vr);
+	  set_varying ();
 	  return;
 	}
       else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
@@ -407,7 +655,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	    min = max = vrp_val_max (TREE_TYPE (min));
 	  else
 	    min = max = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
+	  kind = VR_RANGE;
 	}
       else if (is_min
 	       /* As a special exception preserve non-null ranges.  */
@@ -417,14 +665,14 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	  tree one = build_int_cst (TREE_TYPE (max), 1);
 	  min = int_const_binop (PLUS_EXPR, max, one);
 	  max = vrp_val_max (TREE_TYPE (max));
-	  t = VR_RANGE;
+	  kind = VR_RANGE;
         }
       else if (is_max)
         {
 	  tree one = build_int_cst (TREE_TYPE (min), 1);
 	  max = int_const_binop (MINUS_EXPR, min, one);
 	  min = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
+	  kind = VR_RANGE;
         }
     }
 
@@ -432,15 +680,7 @@ set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
      to make sure VRP iteration terminates, otherwise we can get into
      oscillations.  */
 
-  set_value_range (vr, t, min, max, equiv);
-}
-
-/* Copy value range FROM into value range TO.  */
-
-void
-copy_value_range (value_range *to, const value_range *from)
-{
-  set_value_range (to, from->type, from->min, from->max, from->equiv);
+  set_value_range (this, kind, min, max, equiv);
 }
 
 /* Set value range VR to a single value.  This function is only called
@@ -462,7 +702,7 @@ void
 set_value_range_to_nonnull (value_range *vr, tree type)
 {
   tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv);
+  vr->update (VR_ANTI_RANGE, zero, zero);
 }
 
 
@@ -471,7 +711,7 @@ set_value_range_to_nonnull (value_range *vr, tree type)
 void
 set_value_range_to_null (value_range *vr, tree type)
 {
-  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv);
+  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv ());
 }
 
 /* Return true, if VAL1 and VAL2 are equal values for VRP purposes.  */
@@ -503,9 +743,15 @@ vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
 static inline bool
 range_is_null (const value_range *vr)
 {
-  return vr->type == VR_RANGE
-	 && integer_zerop (vr->min)
-	 && integer_zerop (vr->max);
+  return vr->null_p ();
+}
+
+static inline bool
+range_is_nonnull (const value_range *vr)
+{
+  return (vr->kind () == VR_ANTI_RANGE
+	  && vr->min () == vr->max ()
+	  && integer_zerop (vr->min ()));
 }
 
 /* Return true if max and min of VR are INTEGER_CST.  It's not necessary
@@ -514,9 +760,9 @@ range_is_null (const value_range *vr)
 bool
 range_int_cst_p (const value_range *vr)
 {
-  return (vr->type == VR_RANGE
-	  && TREE_CODE (vr->max) == INTEGER_CST
-	  && TREE_CODE (vr->min) == INTEGER_CST);
+  return (vr->kind () == VR_RANGE
+	  && TREE_CODE (vr->min ()) == INTEGER_CST
+	  && TREE_CODE (vr->max ()) == INTEGER_CST);
 }
 
 /* Return true if VR is a INTEGER_CST singleton.  */
@@ -525,16 +771,7 @@ bool
 range_int_cst_singleton_p (const value_range *vr)
 {
   return (range_int_cst_p (vr)
-	  && tree_int_cst_equal (vr->min, vr->max));
-}
-
-/* Return true if value range VR involves at least one symbol.  */
-
-bool
-symbolic_range_p (const value_range *vr)
-{
-  return (!is_gimple_min_invariant (vr->min)
-          || !is_gimple_min_invariant (vr->max));
+	  && tree_int_cst_equal (vr->min (), vr->max ()));
 }
 
 /* Return the single symbol (an SSA_NAME) contained in T if any, or NULL_TREE
@@ -849,34 +1086,25 @@ value_inside_range (tree val, tree min, tree max)
 bool
 range_includes_zero_p (const value_range *vr)
 {
-  if (vr->type == VR_VARYING)
-    return true;
-
-  /* Ughh, we don't know.  We choose not to optimize.  */
-  if (vr->type == VR_UNDEFINED)
+  if (vr->varying_p () || vr->undefined_p ())
     return true;
-
-  tree zero = build_int_cst (TREE_TYPE (vr->min), 0);
-  if (vr->type == VR_ANTI_RANGE)
-    {
-      int res = value_inside_range (zero, vr->min, vr->max);
-      return res == 0 || res == -2;
-    }
-  return value_inside_range (zero, vr->min, vr->max) != 0;
+  tree zero = build_int_cst (vr->type (), 0);
+  return vr->may_contain_p (zero);
 }
 
-/* If *VR has a value rante that is a single constant value return that,
-   otherwise return NULL_TREE.  */
+/* If *VR has a value range that is a single constant value return that,
+   otherwise return NULL_TREE.
+
+   ?? This actually returns TRUE for [&x, &x], so perhaps "constant"
+   is not the best name.  */
 
 tree
 value_range_constant_singleton (const value_range *vr)
 {
-  if (vr->type == VR_RANGE
-      && vrp_operand_equal_p (vr->min, vr->max)
-      && is_gimple_min_invariant (vr->min))
-    return vr->min;
-
-  return NULL_TREE;
+  tree result = NULL;
+  if (vr->singleton_p (&result))
+    return result;
+  return NULL;
 }
 
 /* Value range wrapper for wide_int_range_set_zero_nonzero_bits.
@@ -899,8 +1127,8 @@ vrp_set_zero_nonzero_bits (const tree expr_type,
       return false;
     }
   wide_int_range_set_zero_nonzero_bits (TYPE_SIGN (expr_type),
-					wi::to_wide (vr->min),
-					wi::to_wide (vr->max),
+					wi::to_wide (vr->min ()),
+					wi::to_wide (vr->max ()),
 					*may_be_nonzero, *must_be_nonzero);
   return true;
 }
@@ -914,40 +1142,36 @@ static bool
 ranges_from_anti_range (const value_range *ar,
 			value_range *vr0, value_range *vr1)
 {
-  tree type = TREE_TYPE (ar->min);
+  tree type = ar->type ();
 
-  vr0->type = VR_UNDEFINED;
-  vr1->type = VR_UNDEFINED;
+  vr0->set_undefined ();
+  vr1->set_undefined ();
 
   /* As a future improvement, we could handle ~[0, A] as: [-INF, -1] U
      [A+1, +INF].  Not sure if this helps in practice, though.  */
 
-  if (ar->type != VR_ANTI_RANGE
-      || TREE_CODE (ar->min) != INTEGER_CST
-      || TREE_CODE (ar->max) != INTEGER_CST
+  if (ar->kind () != VR_ANTI_RANGE
+      || TREE_CODE (ar->min ()) != INTEGER_CST
+      || TREE_CODE (ar->max ()) != INTEGER_CST
       || !vrp_val_min (type)
       || !vrp_val_max (type))
     return false;
 
-  if (!vrp_val_is_min (ar->min))
-    {
-      vr0->type = VR_RANGE;
-      vr0->min = vrp_val_min (type);
-      vr0->max = wide_int_to_tree (type, wi::to_wide (ar->min) - 1);
-    }
-  if (!vrp_val_is_max (ar->max))
-    {
-      vr1->type = VR_RANGE;
-      vr1->min = wide_int_to_tree (type, wi::to_wide (ar->max) + 1);
-      vr1->max = vrp_val_max (type);
-    }
-  if (vr0->type == VR_UNDEFINED)
+  if (!vrp_val_is_min (ar->min ()))
+    *vr0 = value_range (VR_RANGE,
+			vrp_val_min (type),
+			wide_int_to_tree (type, wi::to_wide (ar->min ()) - 1));
+  if (!vrp_val_is_max (ar->max ()))
+    *vr1 = value_range (VR_RANGE,
+			wide_int_to_tree (type, wi::to_wide (ar->max ()) + 1),
+			vrp_val_max (type));
+  if (vr0->undefined_p ())
     {
       *vr0 = *vr1;
-      vr1->type = VR_UNDEFINED;
+      vr1->set_undefined ();
     }
 
-  return vr0->type != VR_UNDEFINED;
+  return !vr0->undefined_p ();
 }
 
 /* Extract the components of a value range into a pair of wide ints in
@@ -961,13 +1185,11 @@ extract_range_into_wide_ints (const value_range *vr,
 			      signop sign, unsigned prec,
 			      wide_int &wmin, wide_int &wmax)
 {
-  if ((vr->type == VR_RANGE
-       || vr->type == VR_ANTI_RANGE)
-      && TREE_CODE (vr->min) == INTEGER_CST
-      && TREE_CODE (vr->max) == INTEGER_CST)
+  gcc_assert (vr->kind () != VR_ANTI_RANGE || vr->symbolic_p ());
+  if (range_int_cst_p (vr))
     {
-      wmin = wi::to_wide (vr->min);
-      wmax = wi::to_wide (vr->max);
+      wmin = wi::to_wide (vr->min ());
+      wmax = wi::to_wide (vr->max ());
     }
   else
     {
@@ -994,14 +1216,15 @@ extract_range_from_multiplicative_op (value_range *vr,
 	      || code == ROUND_DIV_EXPR
 	      || code == RSHIFT_EXPR
 	      || code == LSHIFT_EXPR);
-  gcc_assert (vr0->type == VR_RANGE && vr0->type == vr1->type);
+  gcc_assert (vr0->kind () == VR_RANGE
+	      && vr0->kind () == vr1->kind ());
 
-  tree type = TREE_TYPE (vr0->min);
+  tree type = vr0->type ();
   wide_int res_lb, res_ub;
-  wide_int vr0_lb = wi::to_wide (vr0->min);
-  wide_int vr0_ub = wi::to_wide (vr0->max);
-  wide_int vr1_lb = wi::to_wide (vr1->min);
-  wide_int vr1_ub = wi::to_wide (vr1->max);
+  wide_int vr0_lb = wi::to_wide (vr0->min ());
+  wide_int vr0_ub = wi::to_wide (vr0->max ());
+  wide_int vr1_lb = wi::to_wide (vr1->min ());
+  wide_int vr1_ub = wi::to_wide (vr1->max ());
   bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
   bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
   unsigned prec = TYPE_PRECISION (type);
@@ -1010,9 +1233,9 @@ extract_range_from_multiplicative_op (value_range *vr,
 					 code, TYPE_SIGN (type), prec,
 					 vr0_lb, vr0_ub, vr1_lb, vr1_ub,
 					 overflow_undefined, overflow_wraps))
-    set_and_canonicalize_value_range (vr, VR_RANGE,
-				      wide_int_to_tree (type, res_lb),
-				      wide_int_to_tree (type, res_ub), NULL);
+    vr->set_and_canonicalize (VR_RANGE,
+			      wide_int_to_tree (type, res_lb),
+			      wide_int_to_tree (type, res_ub), NULL);
   else
     set_value_range_to_varying (vr);
 }
@@ -1114,8 +1337,6 @@ set_value_range_with_overflow (value_range &vr,
 {
   const signop sgn = TYPE_SIGN (type);
   const unsigned int prec = TYPE_PRECISION (type);
-  vr.type = VR_RANGE;
-  vr.equiv = NULL;
 
   /* For one bit precision if max < min, then the swapped
      range covers all values.  */
@@ -1133,10 +1354,18 @@ set_value_range_with_overflow (value_range &vr,
       wide_int tmax = wide_int::from (wmax, prec, sgn);
       if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE))
 	{
-	  /* No overflow or both overflow or underflow.  The
-	     range kind stays VR_RANGE.  */
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  /* If the limits are swapped, we wrapped around and cover
+	     the entire range.  We have a similar check at the end of
+	     extract_range_from_binary_expr_1.  */
+	  if (wi::gt_p (tmin, tmax, sgn))
+	    vr.set_varying ();
+	  else
+	    /* No overflow or both overflow or underflow.  The
+	       range kind stays VR_RANGE.  */
+	    vr = value_range (VR_RANGE,
+			      wide_int_to_tree (type, tmin),
+			      wide_int_to_tree (type, tmax));
+	  return;
 	}
       else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
 	       || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
@@ -1145,7 +1374,6 @@ set_value_range_with_overflow (value_range &vr,
 	     changes to VR_ANTI_RANGE.  */
 	  bool covers = false;
 	  wide_int tem = tmin;
-	  vr.type = VR_ANTI_RANGE;
 	  tmin = tmax + 1;
 	  if (wi::cmp (tmin, tmax, sgn) < 0)
 	    covers = true;
@@ -1160,8 +1388,10 @@ set_value_range_with_overflow (value_range &vr,
 	      set_value_range_to_varying (&vr);
 	      return;
 	    }
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  vr = value_range (VR_ANTI_RANGE,
+			    wide_int_to_tree (type, tmin),
+			    wide_int_to_tree (type, tmax));
+	  return;
 	}
       else
 	{
@@ -1176,19 +1406,21 @@ set_value_range_with_overflow (value_range &vr,
 	 value.  */
       wide_int type_min = wi::min_value (prec, sgn);
       wide_int type_max = wi::max_value (prec, sgn);
+      tree min, max;
       if (min_ovf == wi::OVF_UNDERFLOW)
-	vr.min = wide_int_to_tree (type, type_min);
+	min = wide_int_to_tree (type, type_min);
       else if (min_ovf == wi::OVF_OVERFLOW)
-	vr.min = wide_int_to_tree (type, type_max);
+	min = wide_int_to_tree (type, type_max);
       else
-	vr.min = wide_int_to_tree (type, wmin);
+	min = wide_int_to_tree (type, wmin);
 
       if (max_ovf == wi::OVF_UNDERFLOW)
-	vr.max = wide_int_to_tree (type, type_min);
+	max = wide_int_to_tree (type, type_min);
       else if (max_ovf == wi::OVF_OVERFLOW)
-	vr.max = wide_int_to_tree (type, type_max);
+	max = wide_int_to_tree (type, type_max);
       else
-	vr.max = wide_int_to_tree (type, wmax);
+	max = wide_int_to_tree (type, wmax);
+      vr = value_range (VR_RANGE, min, max);
     }
 }
 
@@ -1205,8 +1437,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
   signop sign = TYPE_SIGN (expr_type);
   unsigned int prec = TYPE_PRECISION (expr_type);
   value_range vr0 = *vr0_, vr1 = *vr1_;
-  value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
-  enum value_range_type type;
+  value_range vrtem0, vrtem1;
+  enum value_range_kind type;
   tree min = NULL_TREE, max = NULL_TREE;
   int cmp;
 
@@ -1242,7 +1474,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
     }
 
   /* If both ranges are UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED && vr1.type == VR_UNDEFINED)
+  if (vr0.undefined_p () && vr1.undefined_p ())
     {
       set_value_range_to_undefined (vr);
       return;
@@ -1251,19 +1483,16 @@ extract_range_from_binary_expr_1 (value_range *vr,
      code.  At some point we may want to special-case operations that
      have UNDEFINED result for all or some value-ranges of the not UNDEFINED
      operand.  */
-  else if (vr0.type == VR_UNDEFINED)
+  else if (vr0.undefined_p ())
     set_value_range_to_varying (&vr0);
-  else if (vr1.type == VR_UNDEFINED)
+  else if (vr1.undefined_p ())
     set_value_range_to_varying (&vr1);
 
   /* We get imprecise results from ranges_from_anti_range when
      code is EXACT_DIV_EXPR.  We could mask out bits in the resulting
-     range, but then we also need to hack up vrp_meet.  It's just
+     range, but then we also need to hack up vrp_union.  It's just
      easier to special case when vr0 is ~[0,0] for EXACT_DIV_EXPR.  */
-  if (code == EXACT_DIV_EXPR
-      && vr0.type == VR_ANTI_RANGE
-      && vr0.min == vr0.max
-      && integer_zerop (vr0.min))
+  if (code == EXACT_DIV_EXPR && range_is_nonnull (&vr0))
     {
       set_value_range_to_nonnull (vr, expr_type);
       return;
@@ -1271,36 +1500,35 @@ extract_range_from_binary_expr_1 (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express ~[] op X as ([]' op X) U ([]'' op X).  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.kind () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
-	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
-					    &vrtem1, vr1_);
-	  vrp_meet (vr, &vrres);
+	  value_range vrres;
+	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,					    &vrtem1, vr1_);
+	  vr->union_ (&vrres);
 	}
       return;
     }
   /* Likewise for X op ~[].  */
-  if (vr1.type == VR_ANTI_RANGE
+  if (vr1.kind () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr1, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres;
 	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
 					    vr0_, &vrtem1);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
 
   /* The type of the resulting value range defaults to VR0.TYPE.  */
-  type = vr0.type;
+  type = vr0.kind ();
 
   /* Refuse to operate on VARYING ranges, ranges of different kinds
      and symbolic ranges.  As an exception, we allow BIT_{AND,IOR}
@@ -1323,11 +1551,11 @@ extract_range_from_binary_expr_1 (value_range *vr,
       && code != MINUS_EXPR
       && code != RSHIFT_EXPR
       && code != POINTER_PLUS_EXPR
-      && (vr0.type == VR_VARYING
-	  || vr1.type == VR_VARYING
-	  || vr0.type != vr1.type
-	  || symbolic_range_p (&vr0)
-	  || symbolic_range_p (&vr1)))
+      && (vr0.varying_p ()
+	  || vr1.varying_p ()
+	  || vr0.kind () != vr1.kind ()
+	  || vr0.symbolic_p ()
+	  || vr1.symbolic_p ()))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1385,24 +1613,20 @@ extract_range_from_binary_expr_1 (value_range *vr,
       /* This will normalize things such that calculating
 	 [0,0] - VR_VARYING is not dropped to varying, but is
 	 calculated as [MIN+1, MAX].  */
-      if (vr0.type == VR_VARYING)
-	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = vrp_val_min (expr_type);
-	  vr0.max = vrp_val_max (expr_type);
-	}
-      if (vr1.type == VR_VARYING)
-	{
-	  vr1.type = VR_RANGE;
-	  vr1.min = vrp_val_min (expr_type);
-	  vr1.max = vrp_val_max (expr_type);
-	}
+      if (vr0.varying_p ())
+	vr0.update (VR_RANGE,
+		    vrp_val_min (expr_type),
+		    vrp_val_max (expr_type));
+      if (vr1.varying_p ())
+	vr1.update (VR_RANGE,
+		    vrp_val_min (expr_type),
+		    vrp_val_max (expr_type));
 
       const bool minus_p = (code == MINUS_EXPR);
-      tree min_op0 = vr0.min;
-      tree min_op1 = minus_p ? vr1.max : vr1.min;
-      tree max_op0 = vr0.max;
-      tree max_op1 = minus_p ? vr1.min : vr1.max;
+      tree min_op0 = vr0.min ();
+      tree min_op1 = minus_p ? vr1.max () : vr1.min ();
+      tree max_op0 = vr0.max ();
+      tree max_op1 = minus_p ? vr1.min () : vr1.max ();
       tree sym_min_op0 = NULL_TREE;
       tree sym_min_op1 = NULL_TREE;
       tree sym_max_op0 = NULL_TREE;
@@ -1415,7 +1639,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
 	 single-symbolic ranges, try to compute the precise resulting range,
 	 but only if we know that this resulting range will also be constant
 	 or single-symbolic.  */
-      if (vr0.type == VR_RANGE && vr1.type == VR_RANGE
+      if (vr0.kind () == VR_RANGE && vr1.kind () == VR_RANGE
 	  && (TREE_CODE (min_op0) == INTEGER_CST
 	      || (sym_min_op0
 		  = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
@@ -1455,21 +1679,19 @@ extract_range_from_binary_expr_1 (value_range *vr,
 	  /* Adjust the range for possible overflow.  */
 	  set_value_range_with_overflow (*vr, expr_type,
 					 wmin, wmax, min_ovf, max_ovf);
-	  if (vr->type == VR_VARYING)
+	  if (vr->varying_p ())
 	    return;
 
 	  /* Build the symbolic bounds if needed.  */
-	  adjust_symbolic_bound (vr->min, code, expr_type,
+	  min = vr->min ();
+	  max = vr->max ();
+	  adjust_symbolic_bound (min, code, expr_type,
 				 sym_min_op0, sym_min_op1,
 				 neg_min_op0, neg_min_op1);
-	  adjust_symbolic_bound (vr->max, code, expr_type,
+	  adjust_symbolic_bound (max, code, expr_type,
 				 sym_max_op0, sym_max_op1,
 				 neg_max_op0, neg_max_op1);
-	  /* ?? It would probably be cleaner to eliminate min/max/type
-	     entirely and hold these values in VR directly.  */
-	  min = vr->min;
-	  max = vr->max;
-	  type = vr->type;
+	  type = vr->kind ();
 	}
       else
 	{
@@ -1499,9 +1721,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
       extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max);
       if (wide_int_range_min_max (wmin, wmax, code, sign, prec,
 				  vr0_min, vr0_max, vr1_min, vr1_max))
-	set_value_range (vr, VR_RANGE,
-			 wide_int_to_tree (expr_type, wmin),
-			 wide_int_to_tree (expr_type, wmax), NULL);
+	vr->update (VR_RANGE, wide_int_to_tree (expr_type, wmin),
+		    wide_int_to_tree (expr_type, wmax));
       else
 	set_value_range_to_varying (vr);
       return;
@@ -1522,20 +1743,18 @@ extract_range_from_binary_expr_1 (value_range *vr,
     {
       if (range_int_cst_p (&vr1)
 	  && !wide_int_range_shift_undefined_p (prec,
-						wi::to_wide (vr1.min),
-						wi::to_wide (vr1.max)))
+						wi::to_wide (vr1.min ()),
+						wi::to_wide (vr1.max ())))
 	{
 	  if (code == RSHIFT_EXPR)
 	    {
 	      /* Even if vr0 is VARYING or otherwise not usable, we can derive
 		 useful ranges just from the shift count.  E.g.
 		 x >> 63 for signed 64-bit x is always [-1, 0].  */
-	      if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
-		{
-		  vr0.type = type = VR_RANGE;
-		  vr0.min = vrp_val_min (expr_type);
-		  vr0.max = vrp_val_max (expr_type);
-		}
+	      if (vr0.kind () != VR_RANGE || vr0.symbolic_p ())
+		vr0.update (VR_RANGE,
+			    vrp_val_min (expr_type),
+			    vrp_val_max (expr_type));
 	      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
 	      return;
 	    }
@@ -1544,17 +1763,16 @@ extract_range_from_binary_expr_1 (value_range *vr,
 	    {
 	      wide_int res_lb, res_ub;
 	      if (wide_int_range_lshift (res_lb, res_ub, sign, prec,
-					 wi::to_wide (vr0.min),
-					 wi::to_wide (vr0.max),
-					 wi::to_wide (vr1.min),
-					 wi::to_wide (vr1.max),
+					 wi::to_wide (vr0.min ()),
+					 wi::to_wide (vr0.max ()),
+					 wi::to_wide (vr1.min ()),
+					 wi::to_wide (vr1.max ()),
 					 TYPE_OVERFLOW_UNDEFINED (expr_type),
 					 TYPE_OVERFLOW_WRAPS (expr_type)))
 		{
 		  min = wide_int_to_tree (expr_type, res_lb);
 		  max = wide_int_to_tree (expr_type, res_ub);
-		  set_and_canonicalize_value_range (vr, VR_RANGE,
-						    min, max, NULL);
+		  vr->set_and_canonicalize (VR_RANGE, min, max, NULL);
 		  return;
 		}
 	    }
@@ -1605,11 +1823,11 @@ extract_range_from_binary_expr_1 (value_range *vr,
 		       wide_int_to_tree (expr_type, wmax), NULL);
       if (extra_range_p)
 	{
-	  value_range extra_range = VR_INITIALIZER;
+	  value_range extra_range;
 	  set_value_range (&extra_range, VR_RANGE,
 			   wide_int_to_tree (expr_type, extra_min),
 			   wide_int_to_tree (expr_type, extra_max), NULL);
-	  vrp_meet (vr, &extra_range);
+	  vr->union_ (&extra_range);
 	}
       return;
     }
@@ -1742,7 +1960,8 @@ extract_range_from_unary_expr (value_range *vr,
 {
   signop sign = TYPE_SIGN (type);
   unsigned int prec = TYPE_PRECISION (type);
-  value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+  value_range vr0 = *vr0_;
+  value_range vrtem0, vrtem1;
 
   /* VRP only operates on integral and pointer types.  */
   if (!(INTEGRAL_TYPE_P (op0_type)
@@ -1755,7 +1974,7 @@ extract_range_from_unary_expr (value_range *vr,
     }
 
   /* If VR0 is UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED)
+  if (vr0.undefined_p ())
     {
       set_value_range_to_undefined (vr);
       return;
@@ -1765,14 +1984,14 @@ extract_range_from_unary_expr (value_range *vr,
   if (code == PAREN_EXPR || code == OBJ_TYPE_REF)
     {
       /* PAREN_EXPR and OBJ_TYPE_REF are simple copies.  */
-      copy_value_range (vr, &vr0);
+      vr->deep_copy (&vr0);
       return;
     }
   else if (code == NEGATE_EXPR)
     {
       /* -X is simply 0 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range zero = VR_INITIALIZER;
+      value_range zero;
       set_value_range_to_value (&zero, build_int_cst (type, 0), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR, type, &zero, &vr0);
       return;
@@ -1781,7 +2000,7 @@ extract_range_from_unary_expr (value_range *vr,
     {
       /* ~X is simply -1 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range minusone = VR_INITIALIZER;
+      value_range minusone;
       set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
 					type, &minusone, &vr0);
@@ -1790,16 +2009,16 @@ extract_range_from_unary_expr (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express op ~[]  as (op []') U (op []'').  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.kind () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_unary_expr (vr, code, type, &vrtem0, op0_type);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres;
 	  extract_range_from_unary_expr (&vrres, code, type,
 					 &vrtem1, op0_type);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
@@ -1831,8 +2050,8 @@ extract_range_from_unary_expr (value_range *vr,
 	 pointer anti-ranges.  Any remaining anti-ranges at this point
 	 will be integer conversions from SSA names that will be
 	 normalized into VARYING.  For instance: ~[x_55, x_55].  */
-      gcc_assert (vr0.type != VR_ANTI_RANGE
-		  || TREE_CODE (vr0.min) != INTEGER_CST);
+      gcc_assert (vr0.kind () != VR_ANTI_RANGE
+		  || TREE_CODE (vr0.min ()) != INTEGER_CST);
 
       /* NOTES: Previously we were returning VARYING for all symbolics, but
 	 we can do better by treating them as [-MIN, +MAX].  For
@@ -1855,7 +2074,7 @@ extract_range_from_unary_expr (value_range *vr,
 	{
 	  tree min = wide_int_to_tree (outer_type, wmin);
 	  tree max = wide_int_to_tree (outer_type, wmax);
-	  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
+	  vr->set_and_canonicalize (VR_RANGE, min, max, NULL);
 	}
       else
 	set_value_range_to_varying (vr);
@@ -1889,76 +2108,21 @@ void dump_all_value_ranges (FILE *);
 void dump_vr_equiv (FILE *, bitmap);
 void debug_vr_equiv (bitmap);
 
-
-/* Dump value range VR to FILE.  */
-
 void
 dump_value_range (FILE *file, const value_range *vr)
 {
-  if (vr == NULL)
+  if (!vr)
     fprintf (file, "[]");
-  else if (vr->type == VR_UNDEFINED)
-    fprintf (file, "UNDEFINED");
-  else if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
-    {
-      tree type = TREE_TYPE (vr->min);
-
-      fprintf (file, "%s[", (vr->type == VR_ANTI_RANGE) ? "~" : "");
-
-      if (INTEGRAL_TYPE_P (type)
-	  && !TYPE_UNSIGNED (type)
-	  && vrp_val_is_min (vr->min))
-	fprintf (file, "-INF");
-      else
-	print_generic_expr (file, vr->min);
-
-      fprintf (file, ", ");
-
-      if (INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_max (vr->max))
-	fprintf (file, "+INF");
-      else
-	print_generic_expr (file, vr->max);
-
-      fprintf (file, "]");
-
-      if (vr->equiv)
-	{
-	  bitmap_iterator bi;
-	  unsigned i, c = 0;
-
-	  fprintf (file, "  EQUIVALENCES: { ");
-
-	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv, 0, i, bi)
-	    {
-	      print_generic_expr (file, ssa_name (i));
-	      fprintf (file, " ");
-	      c++;
-	    }
-
-	  fprintf (file, "} (%u elements)", c);
-	}
-    }
-  else if (vr->type == VR_VARYING)
-    fprintf (file, "VARYING");
   else
-    fprintf (file, "INVALID RANGE");
+    vr->dump (file);
 }
 
-
 /* Dump value range VR to stderr.  */
 
 DEBUG_FUNCTION void
 debug_value_range (const value_range *vr)
 {
-  dump_value_range (stderr, vr);
-  fprintf (stderr, "\n");
-}
-
-void
-value_range::dump () const
-{
-  debug_value_range (this);
+  vr->dump ();
 }
 
 
@@ -4202,14 +4366,14 @@ vrp_prop::check_array_ref (location_t location, tree ref,
   if (TREE_CODE (low_sub) == SSA_NAME)
     {
       vr = get_value_range (low_sub);
-      if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
+      if (!vr->undefined_p () && !vr->varying_p ())
         {
-          low_sub = vr->type == VR_RANGE ? vr->max : vr->min;
-          up_sub = vr->type == VR_RANGE ? vr->min : vr->max;
+          low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
+          up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
         }
     }
 
-  if (vr && vr->type == VR_ANTI_RANGE)
+  if (vr && vr->kind () == VR_ANTI_RANGE)
     {
       if (up_bound
 	  && TREE_CODE (up_sub) == INTEGER_CST
@@ -4337,21 +4501,20 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
 	break;
 
       vr = get_value_range (varoff);
-      if (!vr || vr->type == VR_UNDEFINED || !vr->min || !vr->max)
+      if (!vr || vr->undefined_p () || vr->varying_p ())
 	break;
 
-      if (TREE_CODE (vr->min) != INTEGER_CST
-          || TREE_CODE (vr->max) != INTEGER_CST)
+      if (!vr->constant_p ())
         break;
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
-	  if (tree_int_cst_lt (vr->min, vr->max))
+	  if (tree_int_cst_lt (vr->min (), vr->max ()))
 	    {
 	      offset_int min
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min ()));
 	      offset_int max
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max ()));
 	      if (min < max)
 		{
 		  offrange[0] += min;
@@ -5123,8 +5286,8 @@ find_case_label_range (gswitch *stmt, tree min, tree max, size_t *min_idx,
 enum ssa_prop_result
 vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 {
-  value_range vr = VR_INITIALIZER;
   tree lhs = gimple_get_lhs (stmt);
+  value_range vr;
   extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr);
 
   if (*output_p)
@@ -5140,7 +5303,7 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 	      fprintf (dump_file, "\n");
 	    }
 
-	  if (vr.type == VR_VARYING)
+	  if (vr.varying_p ())
 	    return SSA_PROP_VARYING;
 
 	  return SSA_PROP_INTERESTING;
@@ -5193,17 +5356,14 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 		   SSA_PROP_NOT_INTERESTING.  If there are no
 		   {REAL,IMAG}PART_EXPR uses at all,
 		   return SSA_PROP_VARYING.  */
-		value_range new_vr = VR_INITIALIZER;
+		value_range new_vr;
 		extract_range_basic (&new_vr, use_stmt);
 		const value_range *old_vr = get_value_range (use_lhs);
-		if (old_vr->type != new_vr.type
-		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
-		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
-		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
+		if (*old_vr != new_vr)
 		  res = SSA_PROP_INTERESTING;
 		else
 		  res = SSA_PROP_NOT_INTERESTING;
-		BITMAP_FREE (new_vr.equiv);
+		new_vr.equiv_clear ();
 		if (res == SSA_PROP_INTERESTING)
 		  {
 		    *output_p = lhs;
@@ -5231,9 +5391,9 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
    possible such range.  The resulting range is not canonicalized.  */
 
 static void
-union_ranges (enum value_range_type *vr0type,
+union_ranges (enum value_range_kind *vr0type,
 	      tree *vr0min, tree *vr0max,
-	      enum value_range_type vr1type,
+	      enum value_range_kind vr1type,
 	      tree vr1min, tree vr1max)
 {
   bool mineq = vrp_operand_equal_p (*vr0min, vr1min);
@@ -5502,9 +5662,9 @@ give_up:
    possible such range.  The resulting range is not canonicalized.  */
 
 static void
-intersect_ranges (enum value_range_type *vr0type,
+intersect_ranges (enum value_range_kind *vr0type,
 		  tree *vr0min, tree *vr0max,
-		  enum value_range_type vr1type,
+		  enum value_range_kind vr1type,
 		  tree vr1min, tree vr1max)
 {
   bool mineq = vrp_operand_equal_p (*vr0min, vr1min);
@@ -5814,33 +5974,29 @@ intersect_ranges (enum value_range_type *vr0type,
       *vr0min = vr1min;
       *vr0max = vr1max;
     }
-
-  return;
 }
 
 
 /* Intersect the two value-ranges *VR0 and *VR1 and store the result
    in *VR0.  This may not be the smallest possible such range.  */
 
-static void
-vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
+void
+value_range::intersect_helper (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
   /* If either range is VR_VARYING the other one wins.  */
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     return;
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
-      copy_value_range (vr0, vr1);
+      vr0->deep_copy (vr1);
       return;
     }
 
   /* When either range is VR_UNDEFINED the resulting range is
      VR_UNDEFINED, too.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
-  if (vr1->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
       set_value_range_to_undefined (vr0);
       return;
@@ -5848,53 +6004,56 @@ vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
 
   /* Save the original vr0 so we can return it as conservative intersection
      result when our worker turns things to varying.  */
-  saved = *vr0;
-  intersect_ranges (&vr0->type, &vr0->min, &vr0->max,
-		    vr1->type, vr1->min, vr1->max);
+  value_range saved (*vr0);
+
+  value_range_kind vr0type = vr0->kind ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  intersect_ranges (&vr0type, &vr0min, &vr0max,
+		    vr1->kind (), vr1->min (), vr1->max ());
   /* Make sure to canonicalize the result though as the inversion of a
      VR_RANGE can still be a VR_RANGE.  */
-  set_and_canonicalize_value_range (vr0, vr0->type,
-				    vr0->min, vr0->max, vr0->equiv);
+  vr0->set_and_canonicalize (vr0type, vr0min, vr0max, vr0->m_equiv);
   /* If that failed, use the saved original VR0.  */
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       *vr0 = saved;
       return;
     }
   /* If the result is VR_UNDEFINED there is no need to mess with
      the equivalencies.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
 
   /* The resulting set of equivalences for range intersection is the union of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_ior_into (vr0->equiv, vr1->equiv);
-  else if (vr1->equiv && !vr0->equiv)
+  if (vr0->m_equiv && vr1->m_equiv && vr0->m_equiv != vr1->m_equiv)
+    bitmap_ior_into (vr0->m_equiv, vr1->m_equiv);
+  else if (vr1->m_equiv && !vr0->m_equiv)
     {
       /* All equivalence bitmaps are allocated from the same obstack.  So
 	 we can use the obstack associated with VR to allocate vr0->equiv.  */
-      vr0->equiv = BITMAP_ALLOC (vr1->equiv->obstack);
-      bitmap_copy (vr0->equiv, vr1->equiv);
+      vr0->m_equiv = BITMAP_ALLOC (vr1->m_equiv->obstack);
+      bitmap_copy (m_equiv, vr1->m_equiv);
     }
 }
 
 void
-vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
+value_range::intersect (const value_range *other)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Intersecting\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, vr1);
+      dump_value_range (dump_file, other);
       fprintf (dump_file, "\n");
     }
-  vrp_intersect_ranges_1 (vr0, vr1);
+  intersect_helper (this, other);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\n");
     }
 }
@@ -5903,39 +6062,41 @@ vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
    VR1, store in VR0 a range that contains both VR0 and VR1.  This
    may not be the smallest possible such range.  */
 
-static void
-vrp_meet_1 (value_range *vr0, const value_range *vr1)
+void
+value_range::union_helper (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
-  if (vr0->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
-      set_value_range (vr0, vr1->type, vr1->min, vr1->max, vr1->equiv);
+      /* VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr1->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     {
-      /* VR0 already has the resulting range.  */
+      vr0->deep_copy (vr1);
       return;
     }
 
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       /* Nothing to do.  VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     {
       set_value_range_to_varying (vr0);
       return;
     }
 
-  saved = *vr0;
-  union_ranges (&vr0->type, &vr0->min, &vr0->max,
-		vr1->type, vr1->min, vr1->max);
-  if (vr0->type == VR_VARYING)
+  value_range saved (*vr0);
+  value_range_kind vr0type = vr0->kind ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  union_ranges (&vr0type, &vr0min, &vr0max,
+		vr1->kind (), vr1->min (), vr1->max ());
+  *vr0 = value_range (vr0type, vr0min, vr0max);
+  if (vr0->varying_p ())
     {
       /* Failed to find an efficient meet.  Before giving up and setting
 	 the result to VARYING, see if we can at least derive a useful
@@ -5943,52 +6104,51 @@ vrp_meet_1 (value_range *vr0, const value_range *vr1)
       if (range_includes_zero_p (&saved) == 0
 	  && range_includes_zero_p (vr1) == 0)
 	{
-	  set_value_range_to_nonnull (vr0, TREE_TYPE (saved.min));
+	  set_value_range_to_nonnull (vr0, saved.type ());
 
 	  /* Since this meet operation did not result from the meeting of
 	     two equivalent names, VR0 cannot have any equivalences.  */
-	  if (vr0->equiv)
-	    bitmap_clear (vr0->equiv);
+	  if (vr0->m_equiv)
+	    bitmap_clear (vr0->m_equiv);
 	  return;
 	}
 
       set_value_range_to_varying (vr0);
       return;
     }
-  set_and_canonicalize_value_range (vr0, vr0->type, vr0->min, vr0->max,
-				    vr0->equiv);
-  if (vr0->type == VR_VARYING)
+  vr0->set_and_canonicalize (vr0->kind (), vr0->min (), vr0->max (),
+			     vr0->equiv ());
+  if (vr0->varying_p ())
     return;
 
   /* The resulting set of equivalences is always the intersection of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_and_into (vr0->equiv, vr1->equiv);
-  else if (vr0->equiv && !vr1->equiv)
-    bitmap_clear (vr0->equiv);
+  if (vr0->m_equiv && vr1->m_equiv && vr0->m_equiv != vr1->m_equiv)
+    bitmap_and_into (vr0->m_equiv, vr1->m_equiv);
+  else if (vr0->m_equiv && !vr1->m_equiv)
+    bitmap_clear (vr0->m_equiv);
 }
 
 void
-vrp_meet (value_range *vr0, const value_range *vr1)
+value_range::union_ (const value_range *other)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Meeting\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, vr1);
+      dump_value_range (dump_file, other);
       fprintf (dump_file, "\n");
     }
-  vrp_meet_1 (vr0, vr1);
+  union_helper (this, other);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\n");
     }
 }
 
-
 /* Visit all arguments for PHI node PHI that flow through executable
    edges.  If a valid value range can be derived from all the incoming
    value ranges, set a new range for the LHS of PHI.  */
@@ -5997,7 +6157,7 @@ enum ssa_prop_result
 vrp_prop::visit_phi (gphi *phi)
 {
   tree lhs = PHI_RESULT (phi);
-  value_range vr_result = VR_INITIALIZER;
+  value_range vr_result;
   extract_range_from_phi_node (phi, &vr_result);
   if (update_value_range (lhs, &vr_result))
     {
@@ -6010,7 +6170,7 @@ vrp_prop::visit_phi (gphi *phi)
 	  fprintf (dump_file, "\n");
 	}
 
-      if (vr_result.type == VR_VARYING)
+      if (vr_result.varying_p ())
 	return SSA_PROP_VARYING;
 
       return SSA_PROP_INTERESTING;
@@ -6194,16 +6354,17 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
       op = lhs_of_dominating_assert (op, bb, stmt);
 
       const value_range *vr = vr_values->get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  size_t i, j;
 	  /* Get the range of labels that contain a part of the operand's
 	     value range.  */
-	  find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+	  find_case_label_range (switch_stmt, vr->min (), vr->max (), &i, &j);
 
 	  /* Is there only one such label?  */
 	  if (i == j)
@@ -6213,10 +6374,11 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	      /* The i'th label will be taken only if the value range of the
 		 operand is entirely within the bounds of this label.  */
 	      if (CASE_HIGH (label) != NULL_TREE
-		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
-		     && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
-		  : (tree_int_cst_equal (CASE_LOW (label), vr->min)
-		     && tree_int_cst_equal (vr->min, vr->max)))
+		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min ()) <= 0
+		     && tree_int_cst_compare (CASE_HIGH (label),
+					      vr->max ()) >= 0)
+		  : (tree_int_cst_equal (CASE_LOW (label), vr->min ())
+		     && tree_int_cst_equal (vr->min (), vr->max ())))
 		return label;
 	    }
 
@@ -6226,7 +6388,7 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	    return gimple_switch_label (switch_stmt, 0);
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->kind () == VR_ANTI_RANGE)
 	{
 	  unsigned n = gimple_switch_num_labels (switch_stmt);
 	  tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -6235,10 +6397,12 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	  /* The default label will be taken only if the anti-range of the
 	     operand is entirely outside the bounds of all the (non-default)
 	     case labels.  */
-	  if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+	  if (tree_int_cst_compare (vr->min (), CASE_LOW (min_label)) <= 0
 	      && (CASE_HIGH (max_label) != NULL_TREE
-		  ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
-		  : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+		  ? tree_int_cst_compare (vr->max (),
+					  CASE_HIGH (max_label)) >= 0
+		  : tree_int_cst_compare (vr->max (),
+					  CASE_LOW (max_label)) >= 0))
 	  return gimple_switch_label (switch_stmt, 0);
 	}
 
@@ -6255,11 +6419,12 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	{
 	  edge dummy_e;
 	  tree dummy_tree;
-	  value_range new_vr = VR_INITIALIZER;
+	  value_range new_vr;
 	  vr_values->extract_range_from_stmt (stmt, &dummy_e,
 					      &dummy_tree, &new_vr);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  tree singleton;
+	  if (new_vr.singleton_p (&singleton))
+	    return singleton;
 	}
     }
 
@@ -6431,20 +6596,16 @@ vrp_prop::vrp_finalize (bool warn_array_bounds_p)
 	continue;
 
       const value_range *vr = get_value_range (name);
-      if (!name
-	  || (vr->type == VR_VARYING)
-	  || (vr->type == VR_UNDEFINED)
-	  || (TREE_CODE (vr->min) != INTEGER_CST)
-	  || (TREE_CODE (vr->max) != INTEGER_CST))
+      if (!name || !vr->constant_p ())
 	continue;
 
       if (POINTER_TYPE_P (TREE_TYPE (name))
 	  && range_includes_zero_p (vr) == 0)
 	set_ptr_nonnull (name);
       else if (!POINTER_TYPE_P (TREE_TYPE (name)))
-	set_range_info (name, vr->type,
-			wi::to_wide (vr->min),
-			wi::to_wide (vr->max));
+	set_range_info (name, vr->kind (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
     }
 
   /* If we're checking array refs, we want to merge information on
@@ -6636,7 +6797,7 @@ determine_value_range_1 (value_range *vr, tree expr)
 {
   if (BINARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER, vr1 = VR_INITIALIZER;
+      value_range vr0, vr1;
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       determine_value_range_1 (&vr1, TREE_OPERAND (expr, 1));
       extract_range_from_binary_expr_1 (vr, TREE_CODE (expr), TREE_TYPE (expr),
@@ -6644,7 +6805,7 @@ determine_value_range_1 (value_range *vr, tree expr)
     }
   else if (UNARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER;
+      value_range vr0;
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       extract_range_from_unary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr),
 				     &vr0, TREE_TYPE (TREE_OPERAND (expr, 0)));
@@ -6653,7 +6814,7 @@ determine_value_range_1 (value_range *vr, tree expr)
     set_value_range_to_value (vr, expr, NULL);
   else
     {
-      value_range_type kind;
+      value_range_kind kind;
       wide_int min, max;
       /* For SSA names try to extract range info computed by VRP.  Otherwise
 	 fall back to varying.  */
@@ -6670,18 +6831,16 @@ determine_value_range_1 (value_range *vr, tree expr)
 /* Compute a value-range for EXPR and set it in *MIN and *MAX.  Return
    the determined range type.  */
 
-value_range_type
+value_range_kind
 determine_value_range (tree expr, wide_int *min, wide_int *max)
 {
-  value_range vr = VR_INITIALIZER;
+  value_range vr;
   determine_value_range_1 (&vr, expr);
-  if ((vr.type == VR_RANGE
-       || vr.type == VR_ANTI_RANGE)
-      && !symbolic_range_p (&vr))
+  if (vr.constant_p ())
     {
-      *min = wi::to_wide (vr.min);
-      *max = wi::to_wide (vr.max);
-      return vr.type;
+      *min = wi::to_wide (vr.min ());
+      *max = wi::to_wide (vr.max ());
+      return vr.kind ();
     }
 
   return VR_VARYING;
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index 655cf055f0a..4b1c1891bbe 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -20,42 +20,143 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_TREE_VRP_H
 #define GCC_TREE_VRP_H
 
-/* Type of value ranges.  See value_range below for a
-   description of these types.  */
-enum value_range_type { VR_UNDEFINED, VR_RANGE,
-			VR_ANTI_RANGE, VR_VARYING, VR_LAST };
+/* Types of value ranges.  */
+enum value_range_kind
+{
+ /* Empty range.  */
+ VR_UNDEFINED,
+ /* Range spans the entire domain.  */
+ VR_VARYING,
+ /* Range is [MIN, MAX].  */
+ VR_RANGE,
+ /* Range is ~[MIN, MAX].  */
+ VR_ANTI_RANGE,
+ /* Range is a nice guy.  */
+ VR_LAST
+};
 
 /* Range of values that can be associated with an SSA_NAME after VRP
    has executed.  */
-struct GTY((for_user)) value_range
+class GTY((for_user)) value_range
 {
-  /* Lattice value represented by this range.  */
-  enum value_range_type type;
+ public:
+  value_range ();
+  value_range (value_range_kind, tree, tree, bitmap = NULL);
+  void update (value_range_kind, tree, tree);
+  bool operator== (const value_range &) const;
+  bool operator!= (const value_range &) const;
+  void intersect (const value_range *);
+  void union_ (const value_range *);
+
+  /* Types of value ranges.  */
+  bool undefined_p () const;
+  bool varying_p () const;
+  bool symbolic_p () const;
+  bool constant_p () const;
+  void set_undefined ();
+  void set_varying ();
+
+  /* Equivalence bitmap methods.  */
+  bitmap equiv () const;
+  void equiv_clear ();
+  void equiv_add (const_tree, const value_range *, bitmap_obstack * = NULL);
+
+  /* Misc methods.  */
+  tree type () const;
+  bool null_p () const;
+  bool may_contain_p (tree) const;
+  bool singleton_p (tree *result = NULL) const;
+  void deep_copy (const value_range *);
+  bool ignore_equivs_equal_p (const value_range &) const;
+  void set_and_canonicalize (enum value_range_kind, tree, tree, bitmap);
+  void dump (FILE *) const;
+  void dump () const;
+
+  enum value_range_kind kind () const;
+  tree min () const;
+  tree max () const;
+
+ private:
+  void set (value_range_kind, tree, tree, bitmap);
+  void check ();
+  bool equal_p (const value_range &, bool ignore_equivs) const;
+  void intersect_helper (value_range *, const value_range *);
+  void union_helper (value_range *, const value_range *);
+
+  enum value_range_kind m_kind;
+ public:
+  /* These should be private, but GTY is a piece of crap.  */
+  tree m_min;
+  tree m_max;
+  /* Set of SSA names whose value ranges are equivalent to this one.
+     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
+  bitmap m_equiv;
+};
 
-  /* Minimum and maximum values represented by this range.  These
-     values should be interpreted as follows:
+inline
+value_range::value_range ()
+{
+  m_kind = VR_UNDEFINED;
+  m_min = m_max = NULL;
+  m_equiv = NULL;
+}
 
-	- If TYPE is VR_UNDEFINED or VR_VARYING then MIN and MAX must
-	  be NULL.
+/* Return the kind of this range.  */
 
-	- If TYPE == VR_RANGE then MIN holds the minimum value and
-	  MAX holds the maximum value of the range [MIN, MAX].
+inline value_range_kind
+value_range::kind () const
+{
+  return m_kind;
+}
 
-	- If TYPE == ANTI_RANGE the variable is known to NOT
-	  take any values in the range [MIN, MAX].  */
-  tree min;
-  tree max;
+inline bitmap
+value_range::equiv () const
+{
+  return m_equiv;
+}
 
-  /* Set of SSA names whose value ranges are equivalent to this one.
-     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
-  bitmap equiv;
+/* Return the lower bound.  */
 
-  /* Dump value range to stderr.  */
-  void dump () const;
-};
+inline tree
+value_range::min () const
+{
+  return m_min;
+}
+
+/* Return the upper bound.  */
+
+inline tree
+value_range::max () const
+{
+  return m_max;
+}
+
+/* Return TRUE if range spans the entire possible domain.  */
+
+inline bool
+value_range::varying_p () const
+{
+  return m_kind == VR_VARYING;
+}
+
+/* Return TRUE if range is undefined (essentially the empty set).  */
+
+inline bool
+value_range::undefined_p () const
+{
+  return m_kind == VR_UNDEFINED;
+}
+
+/* Return TRUE if range is the constant zero.  */
+
+inline bool
+value_range::null_p () const
+{
+  return (m_kind == VR_RANGE
+	  && integer_zerop (m_min)
+	  && integer_zerop (m_max));
+}
 
-extern void vrp_intersect_ranges (value_range *vr0, const value_range *vr1);
-extern void vrp_meet (value_range *vr0, const value_range *vr1);
 extern void dump_value_range (FILE *, const value_range *);
 extern void extract_range_from_unary_expr (value_range *vr,
 					   enum tree_code code,
@@ -64,8 +165,8 @@ extern void extract_range_from_unary_expr (value_range *vr,
 					   tree op0_type);
 
 extern bool vrp_operand_equal_p (const_tree, const_tree);
-extern enum value_range_type intersect_range_with_nonzero_bits
-  (enum value_range_type, wide_int *, wide_int *, const wide_int &, signop);
+extern enum value_range_kind intersect_range_with_nonzero_bits
+  (enum value_range_kind, wide_int *, wide_int *, const wide_int &, signop);
 
 struct assert_info
 {
@@ -90,19 +191,14 @@ extern bool range_includes_zero_p (const value_range *);
 extern bool infer_value_range (gimple *, tree, tree_code *, tree *);
 
 extern void set_value_range_to_nonnull (value_range *, tree);
-extern void set_value_range (value_range *, enum value_range_type, tree,
+extern void set_value_range (value_range *, enum value_range_kind, tree,
 			     tree, bitmap);
-extern void set_and_canonicalize_value_range (value_range *,
-					      enum value_range_type,
-					      tree, tree, bitmap);
 extern bool vrp_bitmap_equal_p (const_bitmap, const_bitmap);
 extern tree value_range_constant_singleton (const value_range *);
-extern bool symbolic_range_p (const value_range *);
 extern int compare_values (tree, tree);
 extern int compare_values_warnv (tree, tree, bool *);
 extern bool vrp_val_is_min (const_tree);
 extern bool vrp_val_is_max (const_tree);
-extern void copy_value_range (value_range *, const value_range *);
 extern void set_value_range_to_value (value_range *, tree, bitmap);
 extern void extract_range_from_binary_expr_1 (value_range *, enum tree_code,
 					      tree, const value_range *,
@@ -121,5 +217,5 @@ extern bool range_int_cst_singleton_p (const value_range *);
 extern int value_inside_range (tree, tree, tree);
 extern tree get_single_symbol (tree, bool *, tree *);
 extern void maybe_set_nonzero_bits (edge, tree);
-extern value_range_type determine_value_range (tree, wide_int *, wide_int *);
+extern value_range_kind determine_value_range (tree, wide_int *, wide_int *);
 #endif /* GCC_TREE_VRP_H */
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 32392a11618..8c9fd159146 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -55,7 +55,7 @@ static inline void
 set_value_range_to_nonnegative (value_range *vr, tree type)
 {
   tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_RANGE, zero, vrp_val_max (type), vr->equiv);
+  vr->update (VR_RANGE, zero, vrp_val_max (type));
 }
 
 /* Set value range VR to a range of a truthvalue of type TYPE.  */
@@ -66,9 +66,7 @@ set_value_range_to_truthvalue (value_range *vr, tree type)
   if (TYPE_PRECISION (type) == 1)
     set_value_range_to_varying (vr);
   else
-    set_value_range (vr, VR_RANGE,
-		     build_int_cst (type, 0), build_int_cst (type, 1),
-		     vr->equiv);
+    vr->update (VR_RANGE, build_int_cst (type, 0), build_int_cst (type, 1));
 }
 
 
@@ -80,8 +78,7 @@ set_value_range_to_truthvalue (value_range *vr, tree type)
 value_range *
 vr_values::get_value_range (const_tree var)
 {
-  static const value_range vr_const_varying
-    = { VR_VARYING, NULL_TREE, NULL_TREE, NULL };
+  static const value_range vr_const_varying (VR_VARYING, NULL, NULL);
   value_range *vr;
   tree sym;
   unsigned ver = SSA_NAME_VERSION (var);
@@ -106,10 +103,7 @@ vr_values::get_value_range (const_tree var)
 
   /* Create a default value range.  */
   vr_value[ver] = vr = vrp_value_range_pool.allocate ();
-  memset (vr, 0, sizeof (*vr));
-
-  /* Defer allocating the equivalence set.  */
-  vr->equiv = NULL;
+  vr->set_undefined ();
 
   /* If VAR is a default definition of a parameter, the variable can
      take any value in VAR's type.  */
@@ -128,7 +122,7 @@ vr_values::get_value_range (const_tree var)
 	  else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
 	    {
 	      wide_int min, max;
-	      value_range_type rtype = get_range_info (var, &min, &max);
+	      value_range_kind rtype = get_range_info (var, &min, &max);
 	      if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
 		set_value_range (vr, rtype,
 				 wide_int_to_tree (TREE_TYPE (var), min),
@@ -159,7 +153,7 @@ vr_values::set_defs_to_varying (gimple *stmt)
     {
       value_range *vr = get_value_range (def);
       /* Avoid writing to vr_const_varying get_value_range may return.  */
-      if (vr->type != VR_VARYING)
+      if (!vr->varying_p ())
 	set_value_range_to_varying (vr);
     }
 }
@@ -185,24 +179,21 @@ vr_values::update_value_range (const_tree var, value_range *new_vr)
   if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
     {
       wide_int min, max;
-      value_range_type rtype = get_range_info (var, &min, &max);
+      value_range_kind rtype = get_range_info (var, &min, &max);
       if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
 	{
 	  tree nr_min, nr_max;
 	  nr_min = wide_int_to_tree (TREE_TYPE (var), min);
 	  nr_max = wide_int_to_tree (TREE_TYPE (var), max);
-	  value_range nr = VR_INITIALIZER;
-	  set_and_canonicalize_value_range (&nr, rtype, nr_min, nr_max, NULL);
-	  vrp_intersect_ranges (new_vr, &nr);
+	  value_range nr;
+	  nr.set_and_canonicalize (rtype, nr_min, nr_max, NULL);
+	  new_vr->intersect (&nr);
 	}
     }
 
   /* Update the value range, if necessary.  */
   old_vr = get_value_range (var);
-  is_new = old_vr->type != new_vr->type
-	   || !vrp_operand_equal_p (old_vr->min, new_vr->min)
-	   || !vrp_operand_equal_p (old_vr->max, new_vr->max)
-	   || !vrp_bitmap_equal_p (old_vr->equiv, new_vr->equiv);
+  is_new = *old_vr != *new_vr;
 
   if (is_new)
     {
@@ -212,40 +203,22 @@ vr_values::update_value_range (const_tree var, value_range *new_vr)
 	 the same.  We may not have is_new when transitioning to
 	 UNDEFINED.  If old_vr->type is VARYING, we shouldn't be
 	 called.  */
-      if (new_vr->type == VR_UNDEFINED)
+      if (new_vr->undefined_p ())
 	{
-	  BITMAP_FREE (new_vr->equiv);
 	  set_value_range_to_varying (old_vr);
 	  set_value_range_to_varying (new_vr);
 	  return true;
 	}
       else
-	set_value_range (old_vr, new_vr->type, new_vr->min, new_vr->max,
-			 new_vr->equiv);
+	set_value_range (old_vr, new_vr->kind (),
+			 new_vr->min (), new_vr->max (), new_vr->equiv ());
     }
 
-  BITMAP_FREE (new_vr->equiv);
+  new_vr->equiv_clear ();
 
   return is_new;
 }
 
-
-/* Add VAR and VAR's equivalence set to EQUIV.  This is the central
-   point where equivalence processing can be turned on/off.  */
-
-void
-vr_values::add_equivalence (bitmap *equiv, const_tree var)
-{
-  unsigned ver = SSA_NAME_VERSION (var);
-  value_range *vr = get_value_range (var);
-
-  if (*equiv == NULL)
-    *equiv = BITMAP_ALLOC (&vrp_equiv_obstack);
-  bitmap_set_bit (*equiv, ver);
-  if (vr && vr->equiv)
-    bitmap_ior_into (*equiv, vr->equiv);
-}
-
 /* Return true if value range VR involves exactly one symbol SYM.  */
 
 static bool
@@ -254,16 +227,16 @@ symbolic_range_based_on_p (value_range *vr, const_tree sym)
   bool neg, min_has_symbol, max_has_symbol;
   tree inv;
 
-  if (is_gimple_min_invariant (vr->min))
+  if (is_gimple_min_invariant (vr->min ()))
     min_has_symbol = false;
-  else if (get_single_symbol (vr->min, &neg, &inv) == sym)
+  else if (get_single_symbol (vr->min (), &neg, &inv) == sym)
     min_has_symbol = true;
   else
     return false;
 
-  if (is_gimple_min_invariant (vr->max))
+  if (is_gimple_min_invariant (vr->max ()))
     max_has_symbol = false;
-  else if (get_single_symbol (vr->max, &neg, &inv) == sym)
+  else if (get_single_symbol (vr->max (), &neg, &inv) == sym)
     max_has_symbol = true;
   else
     return false;
@@ -403,9 +376,9 @@ vr_values::op_with_boolean_value_range_p (tree op)
     return false;
 
   vr = get_value_range (op);
-  return (vr->type == VR_RANGE
-	  && integer_zerop (vr->min)
-	  && integer_onep (vr->max));
+  return (vr->kind () == VR_RANGE
+	  && integer_zerop (vr->min ())
+	  && integer_onep (vr->max ()));
 }
 
 /* Extract value range information for VAR when (OP COND_CODE LIMIT) is
@@ -438,12 +411,13 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 
   /* LIMIT's range is only interesting if it has any useful information.  */
   if (! limit_vr
-      || limit_vr->type == VR_UNDEFINED
-      || limit_vr->type == VR_VARYING
-      || (symbolic_range_p (limit_vr)
-	  && ! (limit_vr->type == VR_RANGE
-		&& (limit_vr->min == limit_vr->max
-		    || operand_equal_p (limit_vr->min, limit_vr->max, 0)))))
+      || limit_vr->undefined_p ()
+      || limit_vr->varying_p ()
+      || (limit_vr->symbolic_p ()
+	  && ! (limit_vr->kind () == VR_RANGE
+		&& (limit_vr->min () == limit_vr->max ()
+		    || operand_equal_p (limit_vr->min (),
+					limit_vr->max (), 0)))))
     limit_vr = NULL;
 
   /* Initially, the new range has the same set of equivalences of
@@ -451,8 +425,8 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
      value.  Since assertions may be chained via mutually exclusive
      predicates, we will need to trim the set of equivalences before
      we are done.  */
-  gcc_assert (vr_p->equiv == NULL);
-  add_equivalence (&vr_p->equiv, var);
+  gcc_assert (vr_p->equiv () == NULL);
+  vr_p->equiv_add (var, get_value_range (var), &vrp_equiv_obstack);
 
   /* Extract a new range based on the asserted comparison for VAR and
      LIMIT's value range.  Notice that if LIMIT has an anti-range, we
@@ -488,26 +462,24 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
       max = force_fit_type (TREE_TYPE (var), wi::to_widest (max), 0, false);
 
       /* We can transform a max, min range to an anti-range or
-         vice-versa.  Use set_and_canonicalize_value_range which does
-	 this for us.  */
+         vice-versa.  Use set_and_canonicalize which does this for
+         us.  */
       if (cond_code == LE_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_RANGE,
-					  min, max, vr_p->equiv);
+        vr_p->set_and_canonicalize (VR_RANGE, min, max, vr_p->equiv ());
       else if (cond_code == GT_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					  min, max, vr_p->equiv);
+        vr_p->set_and_canonicalize (VR_ANTI_RANGE, min, max, vr_p->equiv ());
       else
 	gcc_unreachable ();
     }
   else if (cond_code == EQ_EXPR)
     {
-      enum value_range_type range_type;
+      enum value_range_kind range_type;
 
       if (limit_vr)
 	{
-	  range_type = limit_vr->type;
-	  min = limit_vr->min;
-	  max = limit_vr->max;
+	  range_type = limit_vr->kind ();
+	  min = limit_vr->min ();
+	  max = limit_vr->max ();
 	}
       else
 	{
@@ -516,13 +488,13 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	  max = limit;
 	}
 
-      set_value_range (vr_p, range_type, min, max, vr_p->equiv);
+      vr_p->update (range_type, min, max);
 
       /* When asserting the equality VAR == LIMIT and LIMIT is another
 	 SSA name, the new range will also inherit the equivalence set
 	 from LIMIT.  */
       if (TREE_CODE (limit) == SSA_NAME)
-	add_equivalence (&vr_p->equiv, limit);
+	vr_p->equiv_add (limit, get_value_range (limit), &vrp_equiv_obstack);
     }
   else if (cond_code == NE_EXPR)
     {
@@ -547,11 +519,11 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	 (i.e., LIMIT_VR->MIN == LIMIT_VR->MAX).  In that case,
 	 build the anti-range ~[LIMIT_VR->MIN, LIMIT_VR->MAX].  */
       if (limit_vr
-	  && limit_vr->type == VR_RANGE
-	  && compare_values (limit_vr->min, limit_vr->max) == 0)
+	  && limit_vr->kind () == VR_RANGE
+	  && compare_values (limit_vr->min (), limit_vr->max ()) == 0)
 	{
-	  min = limit_vr->min;
-	  max = limit_vr->max;
+	  min = limit_vr->min ();
+	  max = limit_vr->max ();
 	}
       else
 	{
@@ -567,21 +539,20 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	  && vrp_val_is_max (max))
 	min = max = limit;
 
-      set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					min, max, vr_p->equiv);
+      vr_p->set_and_canonicalize (VR_ANTI_RANGE, min, max, vr_p->equiv ());
     }
   else if (cond_code == LE_EXPR || cond_code == LT_EXPR)
     {
       min = TYPE_MIN_VALUE (type);
 
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+      if (limit_vr == NULL || limit_vr->kind () == VR_ANTI_RANGE)
 	max = limit;
       else
 	{
 	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
 	     range [MIN, N2] for LE_EXPR and [MIN, N2 - 1] for
 	     LT_EXPR.  */
-	  max = limit_vr->max;
+	  max = limit_vr->max ();
 	}
 
       /* If the maximum value forces us to be out of bounds, simply punt.
@@ -607,21 +578,21 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 		TREE_NO_WARNING (max) = 1;
 	    }
 
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	  vr_p->update (VR_RANGE, min, max);
 	}
     }
   else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
     {
       max = TYPE_MAX_VALUE (type);
 
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+      if (limit_vr == NULL || limit_vr->kind () == VR_ANTI_RANGE)
 	min = limit;
       else
 	{
 	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
 	     range [N1, MAX] for GE_EXPR and [N1 + 1, MAX] for
 	     GT_EXPR.  */
-	  min = limit_vr->min;
+	  min = limit_vr->min ();
 	}
 
       /* If the minimum value forces us to be out of bounds, simply punt.
@@ -647,14 +618,14 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
 		TREE_NO_WARNING (min) = 1;
 	    }
 
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	  vr_p->update (VR_RANGE, min, max);
 	}
     }
   else
     gcc_unreachable ();
 
   /* Finally intersect the new range with what we already know about var.  */
-  vrp_intersect_ranges (vr_p, get_value_range (var));
+  vr_p->intersect (get_value_range (var));
 }
 
 /* Extract value range information from an ASSERT_EXPR EXPR and store
@@ -711,12 +682,12 @@ vr_values::extract_range_from_ssa_name (value_range *vr, tree var)
 {
   value_range *var_vr = get_value_range (var);
 
-  if (var_vr->type != VR_VARYING)
-    copy_value_range (vr, var_vr);
+  if (!var_vr->varying_p ())
+    vr->deep_copy (var_vr);
   else
     set_value_range (vr, VR_RANGE, var, var, NULL);
 
-  add_equivalence (&vr->equiv, var);
+  vr->equiv_add (var, get_value_range (var), &vrp_equiv_obstack);
 }
 
 /* Extract range information from a binary expression OP0 CODE OP1 based on
@@ -728,11 +699,9 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
 					   enum tree_code code,
 					   tree expr_type, tree op0, tree op1)
 {
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
+  value_range vr0, vr1;
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
   else if (is_gimple_min_invariant (op0))
@@ -752,18 +721,14 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
   if (INTEGRAL_TYPE_P (TREE_TYPE (op0))
       && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)))
     {
-      if (vr0.type == VR_VARYING && vr1.type != VR_VARYING)
-	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = vrp_val_min (expr_type);
-	  vr0.max = vrp_val_max (expr_type);
-	}
-      else if (vr1.type == VR_VARYING && vr0.type != VR_VARYING)
-	{
-	  vr1.type = VR_RANGE;
-	  vr1.min = vrp_val_min (expr_type);
-	  vr1.max = vrp_val_max (expr_type);
-	}
+      if (vr0.varying_p () && !vr1.varying_p ())
+	vr0 = value_range (VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type));
+      else if (vr1.varying_p () && !vr0.varying_p ())
+	vr1 = value_range (VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type));
     }
 
   extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
@@ -773,7 +738,7 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
      n = def - arg
      Here the range for n can be set to [0, PTRDIFF_MAX - 1]. */
 
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && code == POINTER_DIFF_EXPR
       && TREE_CODE (op0) == SSA_NAME
       && TREE_CODE (op1) == SSA_NAME)
@@ -806,21 +771,21 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
      symbolic comparison.  When a bound of the range of the first operand
      is invariant, we set the corresponding bound of the new range to INF
      in order to avoid recursing on the range of the second operand.  */
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == PLUS_EXPR || code == MINUS_EXPR)
       && TREE_CODE (op1) == SSA_NAME
-      && vr0.type == VR_RANGE
+      && vr0.kind () == VR_RANGE
       && symbolic_range_based_on_p (&vr0, op1))
     {
       const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr1 = VR_INITIALIZER;
+      value_range n_vr1;
 
       /* Try with VR0 and [-INF, OP1].  */
-      if (is_gimple_min_invariant (minus_p ? vr0.max : vr0.min))
+      if (is_gimple_min_invariant (minus_p ? vr0.max () : vr0.min ()))
 	set_value_range (&n_vr1, VR_RANGE, vrp_val_min (expr_type), op1, NULL);
 
       /* Try with VR0 and [OP1, +INF].  */
-      else if (is_gimple_min_invariant (minus_p ? vr0.min : vr0.max))
+      else if (is_gimple_min_invariant (minus_p ? vr0.min () : vr0.max ()))
 	set_value_range (&n_vr1, VR_RANGE, op1, vrp_val_max (expr_type), NULL);
 
       /* Try with VR0 and [OP1, OP1].  */
@@ -830,21 +795,21 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
       extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1);
     }
 
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == PLUS_EXPR || code == MINUS_EXPR)
       && TREE_CODE (op0) == SSA_NAME
-      && vr1.type == VR_RANGE
+      && vr1.kind () == VR_RANGE
       && symbolic_range_based_on_p (&vr1, op0))
     {
       const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr0 = VR_INITIALIZER;
+      value_range n_vr0;
 
       /* Try with [-INF, OP0] and VR1.  */
-      if (is_gimple_min_invariant (minus_p ? vr1.max : vr1.min))
+      if (is_gimple_min_invariant (minus_p ? vr1.max () : vr1.min ()))
 	set_value_range (&n_vr0, VR_RANGE, vrp_val_min (expr_type), op0, NULL);
 
       /* Try with [OP0, +INF] and VR1.  */
-      else if (is_gimple_min_invariant (minus_p ? vr1.min : vr1.max))
+      else if (is_gimple_min_invariant (minus_p ? vr1.min (): vr1.max ()))
 	set_value_range (&n_vr0, VR_RANGE, op0, vrp_val_max (expr_type), NULL);
 
       /* Try with [OP0, OP0] and VR1.  */
@@ -858,15 +823,15 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
      op1's range is ~[op0,op0] or vice-versa, then we
      can derive a non-null range.  This happens often for
      pointer subtraction.  */
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == MINUS_EXPR || code == POINTER_DIFF_EXPR)
       && TREE_CODE (op0) == SSA_NAME
-      && ((vr0.type == VR_ANTI_RANGE
-	   && vr0.min == op1
-	   && vr0.min == vr0.max)
-	  || (vr1.type == VR_ANTI_RANGE
-	      && vr1.min == op0
-	      && vr1.min == vr1.max)))
+      && ((vr0.kind () == VR_ANTI_RANGE
+	   && vr0.min () == op1
+	   && vr0.min () == vr0.max ())
+	  || (vr1.kind () == VR_ANTI_RANGE
+	      && vr1.min () == op0
+	      && vr1.min () == vr1.max ())))
       set_value_range_to_nonnull (vr, expr_type);
 }
 
@@ -878,7 +843,7 @@ void
 vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code,
 					  tree type, tree op0)
 {
-  value_range vr0 = VR_INITIALIZER;
+  value_range vr0;
 
   /* Get value ranges for the operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
@@ -899,13 +864,10 @@ vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code,
 void
 vr_values::extract_range_from_cond_expr (value_range *vr, gassign *stmt)
 {
-  tree op0, op1;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
-  op0 = gimple_assign_rhs2 (stmt);
+  tree op0 = gimple_assign_rhs2 (stmt);
+  value_range vr0;
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
   else if (is_gimple_min_invariant (op0))
@@ -913,7 +875,8 @@ vr_values::extract_range_from_cond_expr (value_range *vr, gassign *stmt)
   else
     set_value_range_to_varying (&vr0);
 
-  op1 = gimple_assign_rhs3 (stmt);
+  tree op1 = gimple_assign_rhs3 (stmt);
+  value_range vr1;
   if (TREE_CODE (op1) == SSA_NAME)
     vr1 = *(get_value_range (op1));
   else if (is_gimple_min_invariant (op1))
@@ -922,8 +885,8 @@ vr_values::extract_range_from_cond_expr (value_range *vr, gassign *stmt)
     set_value_range_to_varying (&vr1);
 
   /* The resulting value range is the union of the operand ranges */
-  copy_value_range (vr, &vr0);
-  vrp_meet (vr, &vr1);
+  vr->deep_copy (&vr0);
+  vr->union_ (&vr1);
 }
 
 
@@ -946,9 +909,9 @@ vr_values::extract_range_from_comparison (value_range *vr, enum tree_code code,
 	 type.  */
       val = fold_convert (type, val);
       if (is_gimple_min_invariant (val))
-	set_value_range_to_value (vr, val, vr->equiv);
+	set_value_range_to_value (vr, val, vr->equiv ());
       else
-	set_value_range (vr, VR_RANGE, val, val, vr->equiv);
+	vr->update (VR_RANGE, val, val);
     }
   else
     /* The result of a comparison is always true or false.  */
@@ -965,8 +928,7 @@ bool
 vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
 					 tree op0, tree op1, bool *ovf)
 {
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
+  value_range vr0, vr1;
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *get_value_range (op0);
   else if (TREE_CODE (op0) == INTEGER_CST)
@@ -981,29 +943,31 @@ vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
   else
     set_value_range_to_varying (&vr1);
 
+  tree vr0min = vr0.min (), vr0max = vr0.max ();
+  tree vr1min = vr1.min (), vr1max = vr1.max ();
   if (!range_int_cst_p (&vr0)
-      || TREE_OVERFLOW (vr0.min)
-      || TREE_OVERFLOW (vr0.max))
+      || TREE_OVERFLOW (vr0min)
+      || TREE_OVERFLOW (vr0max))
     {
-      vr0.min = vrp_val_min (TREE_TYPE (op0));
-      vr0.max = vrp_val_max (TREE_TYPE (op0));
+      vr0min = vrp_val_min (TREE_TYPE (op0));
+      vr0max = vrp_val_max (TREE_TYPE (op0));
     }
   if (!range_int_cst_p (&vr1)
-      || TREE_OVERFLOW (vr1.min)
-      || TREE_OVERFLOW (vr1.max))
+      || TREE_OVERFLOW (vr1min)
+      || TREE_OVERFLOW (vr1max))
     {
-      vr1.min = vrp_val_min (TREE_TYPE (op1));
-      vr1.max = vrp_val_max (TREE_TYPE (op1));
+      vr1min = vrp_val_min (TREE_TYPE (op1));
+      vr1max = vrp_val_max (TREE_TYPE (op1));
     }
-  *ovf = arith_overflowed_p (subcode, type, vr0.min,
-			     subcode == MINUS_EXPR ? vr1.max : vr1.min);
-  if (arith_overflowed_p (subcode, type, vr0.max,
-			  subcode == MINUS_EXPR ? vr1.min : vr1.max) != *ovf)
+  *ovf = arith_overflowed_p (subcode, type, vr0min,
+			     subcode == MINUS_EXPR ? vr1max : vr1min);
+  if (arith_overflowed_p (subcode, type, vr0max,
+			  subcode == MINUS_EXPR ? vr1min : vr1max) != *ovf)
     return false;
   if (subcode == MULT_EXPR)
     {
-      if (arith_overflowed_p (subcode, type, vr0.min, vr1.max) != *ovf
-	  || arith_overflowed_p (subcode, type, vr0.max, vr1.min) != *ovf)
+      if (arith_overflowed_p (subcode, type, vr0min, vr1max) != *ovf
+	  || arith_overflowed_p (subcode, type, vr0max, vr1min) != *ovf)
 	return false;
     }
   if (*ovf)
@@ -1016,10 +980,10 @@ vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
       widest_int wmin, wmax;
       widest_int w[4];
       int i;
-      w[0] = wi::to_widest (vr0.min);
-      w[1] = wi::to_widest (vr0.max);
-      w[2] = wi::to_widest (vr1.min);
-      w[3] = wi::to_widest (vr1.max);
+      w[0] = wi::to_widest (vr0min);
+      w[1] = wi::to_widest (vr0max);
+      w[2] = wi::to_widest (vr1min);
+      w[3] = wi::to_widest (vr1max);
       for (i = 0; i < 4; i++)
 	{
 	  widest_int wt;
@@ -1113,11 +1077,11 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		mini = 1;
 	      /* If some high bits are known to be zero,
 		 we can decrease the maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST
-		  && !operand_less_p (vr0->min,
-				      build_zero_cst (TREE_TYPE (vr0->min))))
-		maxi = tree_floor_log2 (vr0->max) + 1;
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST
+		  && !operand_less_p (vr0->min (),
+				      build_zero_cst (TREE_TYPE (vr0->min ()))))
+		maxi = tree_floor_log2 (vr0->max ()) + 1;
 	    }
 	  goto bitop_builtin;
 	  /* __builtin_parity* returns [0, 1].  */
@@ -1148,15 +1112,15 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	      value_range *vr0 = get_value_range (arg);
 	      /* From clz of VR_RANGE minimum we can compute
 		 result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->min) == INTEGER_CST)
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->min ()) == INTEGER_CST)
 		{
-		  maxi = prec - 1 - tree_floor_log2 (vr0->min);
+		  maxi = prec - 1 - tree_floor_log2 (vr0->min ());
 		  if (maxi != prec)
 		    mini = 0;
 		}
-	      else if (vr0->type == VR_ANTI_RANGE
-		       && integer_zerop (vr0->min))
+	      else if (vr0->kind () == VR_ANTI_RANGE
+		       && integer_zerop (vr0->min ()))
 		{
 		  maxi = prec - 1;
 		  mini = 0;
@@ -1165,10 +1129,10 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		break;
 	      /* From clz of VR_RANGE maximum we can compute
 		 result minimum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST)
 		{
-		  mini = prec - 1 - tree_floor_log2 (vr0->max);
+		  mini = prec - 1 - tree_floor_log2 (vr0->max ());
 		  if (mini == prec)
 		    break;
 		}
@@ -1204,20 +1168,20 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	    {
 	      value_range *vr0 = get_value_range (arg);
 	      /* If arg is non-zero, then use [0, prec - 1].  */
-	      if ((vr0->type == VR_RANGE
-		   && integer_nonzerop (vr0->min))
-		  || (vr0->type == VR_ANTI_RANGE
-		      && integer_zerop (vr0->min)))
+	      if ((vr0->kind () == VR_RANGE
+		   && integer_nonzerop (vr0->min ()))
+		  || (vr0->kind () == VR_ANTI_RANGE
+		      && integer_zerop (vr0->min ())))
 		{
 		  mini = 0;
 		  maxi = prec - 1;
 		}
 	      /* If some high bits are known to be zero,
 		 we can decrease the result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
+	      if (vr0->kind () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST)
 		{
-		  maxi = tree_floor_log2 (vr0->max);
+		  maxi = tree_floor_log2 (vr0->max ());
 		  /* For vr0 [0, 0] give up.  */
 		  if (maxi == -1)
 		    break;
@@ -1302,9 +1266,9 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	     this should have been already folded and if not, it
 	     wasn't folded because of overflow.  Avoid removing the
 	     UBSAN_CHECK_* calls in that case.  */
-	  if (vr->type == VR_RANGE
-	      && (vr->min == vr->max
-		  || operand_equal_p (vr->min, vr->max, 0)))
+	  if (vr->kind () == VR_RANGE
+	      && (vr->min () == vr->max ()
+		  || operand_equal_p (vr->min (), vr->max (), 0)))
 	    set_value_range_to_varying (vr);
 	  return;
 	}
@@ -1381,8 +1345,7 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		    }
 		  else
 		    {
-		      value_range vr0 = VR_INITIALIZER;
-		      value_range vr1 = VR_INITIALIZER;
+		      value_range vr0, vr1;
 		      bool saved_flag_wrapv = flag_wrapv;
 		      /* Pretend the arithmetics is wrapping.  If there is
 			 any overflow, IMAGPART_EXPR will be set.  */
@@ -1444,7 +1407,7 @@ vr_values::extract_range_from_assignment (value_range *vr, gassign *stmt)
   else
     set_value_range_to_varying (vr);
 
-  if (vr->type == VR_VARYING)
+  if (vr->varying_p ())
     extract_range_basic (vr, stmt);
 }
 
@@ -1467,18 +1430,18 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 		bool *strict_overflow_p)
 {
   /* VARYING or UNDEFINED ranges cannot be compared.  */
-  if (vr0->type == VR_VARYING
-      || vr0->type == VR_UNDEFINED
-      || vr1->type == VR_VARYING
-      || vr1->type == VR_UNDEFINED)
+  if (vr0->varying_p ()
+      || vr0->undefined_p ()
+      || vr1->varying_p ()
+      || vr1->undefined_p ())
     return NULL_TREE;
 
   /* Anti-ranges need to be handled separately.  */
-  if (vr0->type == VR_ANTI_RANGE || vr1->type == VR_ANTI_RANGE)
+  if (vr0->kind () == VR_ANTI_RANGE || vr1->kind () == VR_ANTI_RANGE)
     {
       /* If both are anti-ranges, then we cannot compute any
 	 comparison.  */
-      if (vr0->type == VR_ANTI_RANGE && vr1->type == VR_ANTI_RANGE)
+      if (vr0->kind () == VR_ANTI_RANGE && vr1->kind () == VR_ANTI_RANGE)
 	return NULL_TREE;
 
       /* These comparisons are never statically computable.  */
@@ -1490,7 +1453,7 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 
       /* Equality can be computed only between a range and an
 	 anti-range.  ~[VAL1, VAL2] == [VAL1, VAL2] is always false.  */
-      if (vr0->type == VR_RANGE)
+      if (vr0->kind () == VR_RANGE)
 	{
 	  /* To simplify processing, make VR0 the anti-range.  */
 	  value_range *tmp = vr0;
@@ -1500,8 +1463,8 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 
       gcc_assert (comp == NE_EXPR || comp == EQ_EXPR);
 
-      if (compare_values_warnv (vr0->min, vr1->min, strict_overflow_p) == 0
-	  && compare_values_warnv (vr0->max, vr1->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr0->min (), vr1->min (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr0->max (), vr1->max (), strict_overflow_p) == 0)
 	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -1519,12 +1482,12 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
     {
       /* Equality may only be computed if both ranges represent
 	 exactly one value.  */
-      if (compare_values_warnv (vr0->min, vr0->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr1->min, vr1->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr0->min (), vr0->max (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr1->min (), vr1->max (), strict_overflow_p) == 0)
 	{
-	  int cmp_min = compare_values_warnv (vr0->min, vr1->min,
+	  int cmp_min = compare_values_warnv (vr0->min (), vr1->min (),
 					      strict_overflow_p);
-	  int cmp_max = compare_values_warnv (vr0->max, vr1->max,
+	  int cmp_max = compare_values_warnv (vr0->max (), vr1->max (),
 					      strict_overflow_p);
 	  if (cmp_min == 0 && cmp_max == 0)
 	    return boolean_true_node;
@@ -1532,9 +1495,9 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 	    return boolean_false_node;
 	}
       /* If [V0_MIN, V1_MAX] < [V1_MIN, V1_MAX] then V0 != V1.  */
-      else if (compare_values_warnv (vr0->min, vr1->max,
+      else if (compare_values_warnv (vr0->min (), vr1->max (),
 				     strict_overflow_p) == 1
-	       || compare_values_warnv (vr1->min, vr0->max,
+	       || compare_values_warnv (vr1->min (), vr0->max (),
 					strict_overflow_p) == 1)
 	return boolean_false_node;
 
@@ -1549,20 +1512,20 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 	 make sure that both comparisons yield similar results to
 	 avoid comparing values that cannot be compared at
 	 compile-time.  */
-      cmp1 = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
-      cmp2 = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
+      cmp1 = compare_values_warnv (vr0->max (), vr1->min (), strict_overflow_p);
+      cmp2 = compare_values_warnv (vr0->min (), vr1->max (), strict_overflow_p);
       if ((cmp1 == -1 && cmp2 == -1) || (cmp1 == 1 && cmp2 == 1))
 	return boolean_true_node;
 
       /* If VR0 and VR1 represent a single value and are identical,
 	 return false.  */
-      else if (compare_values_warnv (vr0->min, vr0->max,
+      else if (compare_values_warnv (vr0->min (), vr0->max (),
 				     strict_overflow_p) == 0
-	       && compare_values_warnv (vr1->min, vr1->max,
+	       && compare_values_warnv (vr1->min (), vr1->max (),
 					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->min, vr1->min,
+	       && compare_values_warnv (vr0->min (), vr1->min (),
 					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->max, vr1->max,
+	       && compare_values_warnv (vr0->max (), vr1->max (),
 					strict_overflow_p) == 0)
 	return boolean_false_node;
 
@@ -1575,13 +1538,13 @@ compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
       int tst;
 
       /* If VR0 is to the left of VR1, return true.  */
-      tst = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
+      tst = compare_values_warnv (vr0->max (), vr1->min (), strict_overflow_p);
       if ((comp == LT_EXPR && tst == -1)
 	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
 	return boolean_true_node;
 
       /* If VR0 is to the right of VR1, return false.  */
-      tst = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
+      tst = compare_values_warnv (vr0->min (), vr1->max (), strict_overflow_p);
       if ((comp == LT_EXPR && (tst == 0 || tst == 1))
 	  || (comp == LE_EXPR && tst == 1))
 	return boolean_false_node;
@@ -1605,11 +1568,11 @@ static tree
 compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 			  bool *strict_overflow_p)
 {
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+  if (vr->varying_p () || vr->undefined_p ())
     return NULL_TREE;
 
   /* Anti-ranges need to be handled separately.  */
-  if (vr->type == VR_ANTI_RANGE)
+  if (vr->kind () == VR_ANTI_RANGE)
     {
       /* For anti-ranges, the only predicates that we can compute at
 	 compile time are equality and inequality.  */
@@ -1620,7 +1583,7 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 	return NULL_TREE;
 
       /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2.  */
-      if (value_inside_range (val, vr->min, vr->max) == 1)
+      if (value_inside_range (val, vr->min (), vr->max ()) == 1)
 	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -1630,16 +1593,16 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
     {
       /* EQ_EXPR may only be computed if VR represents exactly
 	 one value.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr->min (), vr->max (), strict_overflow_p) == 0)
 	{
-	  int cmp = compare_values_warnv (vr->min, val, strict_overflow_p);
+	  int cmp = compare_values_warnv (vr->min (), val, strict_overflow_p);
 	  if (cmp == 0)
 	    return boolean_true_node;
 	  else if (cmp == -1 || cmp == 1 || cmp == 2)
 	    return boolean_false_node;
 	}
-      else if (compare_values_warnv (val, vr->min, strict_overflow_p) == -1
-	       || compare_values_warnv (vr->max, val, strict_overflow_p) == -1)
+      else if (compare_values_warnv (val, vr->min (), strict_overflow_p) == -1
+	       || compare_values_warnv (vr->max (), val, strict_overflow_p) == -1)
 	return boolean_false_node;
 
       return NULL_TREE;
@@ -1647,14 +1610,14 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
   else if (comp == NE_EXPR)
     {
       /* If VAL is not inside VR, then they are always different.  */
-      if (compare_values_warnv (vr->max, val, strict_overflow_p) == -1
-	  || compare_values_warnv (vr->min, val, strict_overflow_p) == 1)
+      if (compare_values_warnv (vr->max (), val, strict_overflow_p) == -1
+	  || compare_values_warnv (vr->min (), val, strict_overflow_p) == 1)
 	return boolean_true_node;
 
       /* If VR represents exactly one value equal to VAL, then return
 	 false.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr->min, val, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr->min (), vr->max (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr->min (), val, strict_overflow_p) == 0)
 	return boolean_false_node;
 
       /* Otherwise, they may or may not be different.  */
@@ -1665,13 +1628,13 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
       int tst;
 
       /* If VR is to the left of VAL, return true.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->max (), val, strict_overflow_p);
       if ((comp == LT_EXPR && tst == -1)
 	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
 	return boolean_true_node;
 
       /* If VR is to the right of VAL, return false.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->min (), val, strict_overflow_p);
       if ((comp == LT_EXPR && (tst == 0 || tst == 1))
 	  || (comp == LE_EXPR && tst == 1))
 	return boolean_false_node;
@@ -1684,13 +1647,13 @@ compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
       int tst;
 
       /* If VR is to the right of VAL, return true.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->min (), val, strict_overflow_p);
       if ((comp == GT_EXPR && tst == 1)
 	  || (comp == GE_EXPR && (tst == 0 || tst == 1)))
 	return boolean_true_node;
 
       /* If VR is to the left of VAL, return false.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->max (), val, strict_overflow_p);
       if ((comp == GT_EXPR && (tst == -1 || tst == 0))
 	  || (comp == GE_EXPR && tst == -1))
 	return boolean_false_node;
@@ -1714,7 +1677,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 
   /* TODO.  Don't adjust anti-ranges.  An anti-range may provide
      better opportunities than a regular range, but I'm not sure.  */
-  if (vr->type == VR_ANTI_RANGE)
+  if (vr->kind () == VR_ANTI_RANGE)
     return;
 
   chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
@@ -1722,7 +1685,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   /* Like in PR19590, scev can return a constant function.  */
   if (is_gimple_min_invariant (chrec))
     {
-      set_value_range_to_value (vr, chrec, vr->equiv);
+      set_value_range_to_value (vr, chrec, vr->equiv ());
       return;
     }
 
@@ -1771,7 +1734,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   if (TREE_CODE (step) == INTEGER_CST
       && is_gimple_val (init)
       && (TREE_CODE (init) != SSA_NAME
-	  || get_value_range (init)->type == VR_RANGE))
+	  || get_value_range (init)->kind () == VR_RANGE))
     {
       widest_int nit;
 
@@ -1779,7 +1742,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	 the number of latch executions is the correct thing to use.  */
       if (max_loop_iterations (loop, &nit))
 	{
-	  value_range maxvr = VR_INITIALIZER;
+	  value_range maxvr;
 	  signop sgn = TYPE_SIGN (TREE_TYPE (step));
 	  wi::overflow_type overflow;
 
@@ -1799,9 +1762,9 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	      extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
 					      TREE_TYPE (init), init, tem);
 	      /* Likewise if the addition did.  */
-	      if (maxvr.type == VR_RANGE)
+	      if (maxvr.kind () == VR_RANGE)
 		{
-		  value_range initvr = VR_INITIALIZER;
+		  value_range initvr;
 
 		  if (TREE_CODE (init) == SSA_NAME)
 		    initvr = *(get_value_range (init));
@@ -1815,19 +1778,19 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 		     because the loop may exit immediately.  Overflow could
 		     happen in the plus expression in this case.  */
 		  if ((dir == EV_DIR_DECREASES
-		       && compare_values (maxvr.min, initvr.min) != -1)
+		       && compare_values (maxvr.min (), initvr.min ()) != -1)
 		      || (dir == EV_DIR_GROWS
-			  && compare_values (maxvr.max, initvr.max) != 1))
+			  && compare_values (maxvr.max (), initvr.max ()) != 1))
 		    return;
 
-		  tmin = maxvr.min;
-		  tmax = maxvr.max;
+		  tmin = maxvr.min ();
+		  tmax = maxvr.max ();
 		}
 	    }
 	}
     }
 
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+  if (vr->varying_p () || vr->undefined_p ())
     {
       min = tmin;
       max = tmax;
@@ -1840,15 +1803,15 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
       else
 	min = init;
     }
-  else if (vr->type == VR_RANGE)
+  else if (vr->kind () == VR_RANGE)
     {
-      min = vr->min;
-      max = vr->max;
+      min = vr->min ();
+      max = vr->max ();
 
       if (dir == EV_DIR_DECREASES)
 	{
-	  /* INIT is the maximum value.  If INIT is lower than VR->MAX
-	     but no smaller than VR->MIN, set VR->MAX to INIT.  */
+	  /* INIT is the maximum value.  If INIT is lower than VR->MAX ()
+	     but no smaller than VR->MIN (), set VR->MAX () to INIT.  */
 	  if (compare_values (init, max) == -1)
 	    max = init;
 
@@ -1860,7 +1823,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	}
       else
 	{
-	  /* If INIT is bigger than VR->MIN, set VR->MIN to INIT.  */
+	  /* If INIT is bigger than VR->MIN (), set VR->MIN () to INIT.  */
 	  if (compare_values (init, min) == 1)
 	    min = init;
 
@@ -1886,7 +1849,7 @@ vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   if (TREE_OVERFLOW_P (max))
     max = drop_tree_overflow (max);
 
-  set_value_range (vr, VR_RANGE, min, max, vr->equiv);
+  vr->update (VR_RANGE, min, max);
 }
 
 /* Dump value ranges of all SSA_NAMEs to FILE.  */
@@ -1957,11 +1920,11 @@ vrp_valueize (tree name)
   if (TREE_CODE (name) == SSA_NAME)
     {
       value_range *vr = x_vr_values->get_value_range (name);
-      if (vr->type == VR_RANGE
-	  && (TREE_CODE (vr->min) == SSA_NAME
-	      || is_gimple_min_invariant (vr->min))
-	  && vrp_operand_equal_p (vr->min, vr->max))
-	return vr->min;
+      if (vr->kind () == VR_RANGE
+	  && (TREE_CODE (vr->min ()) == SSA_NAME
+	      || is_gimple_min_invariant (vr->min ()))
+	  && vrp_operand_equal_p (vr->min (), vr->max ()))
+	return vr->min ();
     }
   return name;
 }
@@ -1982,8 +1945,9 @@ vrp_valueize_1 (tree name)
 	  && prop_simulate_again_p (def_stmt))
 	return NULL_TREE;
       value_range *vr = x_vr_values->get_value_range (name);
-      if (range_int_cst_singleton_p (vr))
-	return vr->min;
+      tree singleton;
+      if (vr->singleton_p (&singleton))
+	return singleton;
     }
   return name;
 }
@@ -2066,12 +2030,8 @@ vr_values::get_vr_for_comparison (int i)
   /* If name N_i does not have a valid range, use N_i as its own
      range.  This allows us to compare against names that may
      have N_i in their ranges.  */
-  if (vr.type == VR_VARYING || vr.type == VR_UNDEFINED)
-    {
-      vr.type = VR_RANGE;
-      vr.min = ssa_name (i);
-      vr.max = ssa_name (i);
-    }
+  if (vr.varying_p () || vr.undefined_p ())
+    vr = value_range (VR_RANGE, ssa_name (i), ssa_name (i), NULL);
 
   return vr;
 }
@@ -2094,7 +2054,7 @@ vr_values::compare_name_with_value (enum tree_code comp, tree var, tree val,
   value_range equiv_vr;
 
   /* Get the set of equivalences for VAR.  */
-  e = get_value_range (var)->equiv;
+  e = get_value_range (var)->equiv ();
 
   /* Start at -1.  Set it to 0 if we do a comparison without relying
      on overflow, or 1 if all comparisons rely on overflow.  */
@@ -2180,8 +2140,8 @@ vr_values::compare_names (enum tree_code comp, tree n1, tree n2,
 
   /* Compare the ranges of every name equivalent to N1 against the
      ranges of every name equivalent to N2.  */
-  e1 = get_value_range (n1)->equiv;
-  e2 = get_value_range (n2)->equiv;
+  e1 = get_value_range (n1)->equiv ();
+  e2 = get_value_range (n2)->equiv ();
 
   /* Use the fake bitmaps if e1 or e2 are not available.  */
   if (s_obstack == NULL)
@@ -2440,10 +2400,10 @@ vr_values::vrp_evaluate_conditional (tree_code code, tree op0,
       tree type = TREE_TYPE (op0);
       value_range *vr0 = get_value_range (op0);
 
-      if (vr0->type == VR_RANGE
+      if (vr0->kind () == VR_RANGE
 	  && INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_min (vr0->min)
-	  && vrp_val_is_max (vr0->max)
+	  && vrp_val_is_min (vr0->min ())
+	  && vrp_val_is_max (vr0->max ())
 	  && is_gimple_min_invariant (op1))
 	{
 	  location_t location;
@@ -2572,9 +2532,9 @@ find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
   unsigned int n = gimple_switch_num_labels (stmt);
   bool take_default;
   tree case_low, case_high;
-  tree min = vr->min, max = vr->max;
+  tree min = vr->min (), max = vr->max ();
 
-  gcc_checking_assert (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE);
+  gcc_checking_assert (!vr->varying_p () && !vr->undefined_p ());
 
   take_default = !find_case_label_range (stmt, min, max, &i, &j);
 
@@ -2582,7 +2542,7 @@ find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
   *min_idx2 = 1;
   *max_idx2 = 0;
 
-  if (vr->type == VR_RANGE)
+  if (vr->kind () == VR_RANGE)
     {
       *min_idx1 = i;
       *max_idx1 = j;
@@ -2663,9 +2623,9 @@ vr_values::vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
       fprintf (dump_file, "\n");
     }
 
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || symbolic_range_p (vr))
+  if (vr->undefined_p ()
+      || vr->varying_p ()
+      || vr->symbolic_p ())
     return;
 
   /* Find the single edge that is taken from the switch expression.  */
@@ -2809,40 +2769,24 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 		 See PR53465 and PR54767.  */
 	      if (e->flags & EDGE_DFS_BACK)
 		{
-		  if (vr_arg.type == VR_RANGE
-		      || vr_arg.type == VR_ANTI_RANGE)
+		  if (!vr_arg.varying_p () && !vr_arg.undefined_p ())
 		    {
-		      vr_arg.equiv = NULL;
-		      if (symbolic_range_p (&vr_arg))
-			{
-			  vr_arg.type = VR_VARYING;
-			  vr_arg.min = NULL_TREE;
-			  vr_arg.max = NULL_TREE;
-			}
-		    }
-		}
-	      else
-		{
-		  /* If the non-backedge arguments range is VR_VARYING then
-		     we can still try recording a simple equivalence.  */
-		  if (vr_arg.type == VR_VARYING)
-		    {
-		      vr_arg.type = VR_RANGE;
-		      vr_arg.min = arg;
-		      vr_arg.max = arg;
-		      vr_arg.equiv = NULL;
+		      vr_arg.equiv_clear ();
+		      if (vr_arg.symbolic_p ())
+			vr_arg.set_varying ();
 		    }
 		}
+	      /* If the non-backedge arguments range is VR_VARYING then
+		 we can still try recording a simple equivalence.  */
+	      else if (vr_arg.varying_p ())
+		vr_arg = value_range (VR_RANGE, arg, arg, NULL);
 	    }
 	  else
 	    {
 	      if (TREE_OVERFLOW_P (arg))
 		arg = drop_tree_overflow (arg);
 
-	      vr_arg.type = VR_RANGE;
-	      vr_arg.min = arg;
-	      vr_arg.max = arg;
-	      vr_arg.equiv = NULL;
+	      vr_arg = value_range (VR_RANGE, arg, arg);
 	    }
 
 	  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2855,19 +2799,19 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 	    }
 
 	  if (first)
-	    copy_value_range (vr_result, &vr_arg);
+	    vr_result->deep_copy (&vr_arg);
 	  else
-	    vrp_meet (vr_result, &vr_arg);
+	    vr_result->union_ (&vr_arg);
 	  first = false;
 
-	  if (vr_result->type == VR_VARYING)
+	  if (vr_result->varying_p ())
 	    break;
 	}
     }
 
-  if (vr_result->type == VR_VARYING)
+  if (vr_result->varying_p ())
     goto varying;
-  else if (vr_result->type == VR_UNDEFINED)
+  else if (vr_result->undefined_p ())
     goto update_range;
 
   old_edges = vr_phi_edge_counts[SSA_NAME_VERSION (lhs)];
@@ -2883,21 +2827,21 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
   if (edges > 0
       && gimple_phi_num_args (phi) > 1
       && edges == old_edges
-      && lhs_vr->type != VR_UNDEFINED
+      && !lhs_vr->undefined_p ()
       && may_simulate_backedge_again)
     {
       /* Compare old and new ranges, fall back to varying if the
          values are not comparable.  */
-      int cmp_min = compare_values (lhs_vr->min, vr_result->min);
+      int cmp_min = compare_values (lhs_vr->min (), vr_result->min ());
       if (cmp_min == -2)
 	goto varying;
-      int cmp_max = compare_values (lhs_vr->max, vr_result->max);
+      int cmp_max = compare_values (lhs_vr->max (), vr_result->max ());
       if (cmp_max == -2)
 	goto varying;
 
       /* For non VR_RANGE or for pointers fall back to varying if
 	 the range changed.  */
-      if ((lhs_vr->type != VR_RANGE || vr_result->type != VR_RANGE
+      if ((lhs_vr->kind () != VR_RANGE || vr_result->kind () != VR_RANGE
 	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
 	  && (cmp_min != 0 || cmp_max != 0))
 	goto varying;
@@ -2910,24 +2854,27 @@ vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 	 times to reach -INF.  Going to -INF + 1 also lets the following
 	 iteration compute whether there will be any overflow, at the
 	 expense of one additional iteration.  */
+      tree new_min = vr_result->min ();
+      tree new_max = vr_result->max ();
       if (cmp_min < 0)
-	vr_result->min = lhs_vr->min;
+	new_min = lhs_vr->min ();
       else if (cmp_min > 0
-	       && !vrp_val_is_min (vr_result->min))
-	vr_result->min
-	  = int_const_binop (PLUS_EXPR,
-			     vrp_val_min (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
+	       && !vrp_val_is_min (vr_result->min ()))
+	new_min = int_const_binop (PLUS_EXPR,
+				   vrp_val_min (vr_result->type ()),
+				   build_int_cst (vr_result->type (), 1));
 
       /* Similarly for the maximum value.  */
       if (cmp_max > 0)
-	vr_result->max = lhs_vr->max;
+	new_max = lhs_vr->max ();
       else if (cmp_max < 0
-	       && !vrp_val_is_max (vr_result->max))
-	vr_result->max
-	  = int_const_binop (MINUS_EXPR,
-			     vrp_val_max (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
+	       && !vrp_val_is_max (vr_result->max ()))
+	new_max = int_const_binop (MINUS_EXPR,
+				   vrp_val_max (vr_result->type ()),
+				   build_int_cst (vr_result->type (), 1));
+
+      *vr_result = value_range (vr_result->kind (), new_min, new_max,
+				vr_result->equiv ());
 
       /* If we dropped either bound to +-INF then if this is a loop
 	 PHI node SCEV may known more about its value-range.  */
@@ -2957,9 +2904,9 @@ infinite_check:
   /* If we will end up with a (-INF, +INF) range, set it to
      VARYING.  Same if the previous max value was invalid for
      the type and we end up with vr_result.min > vr_result.max.  */
-  if ((vr_result->type == VR_RANGE || vr_result->type == VR_ANTI_RANGE)
-      && !((vrp_val_is_max (vr_result->max) && vrp_val_is_min (vr_result->min))
-	   || compare_values (vr_result->min, vr_result->max) > 0))
+  if ((!vr_result->varying_p () && !vr_result->undefined_p ())
+      && !((vrp_val_is_max (vr_result->max ()) && vrp_val_is_min (vr_result->min ()))
+	   || compare_values (vr_result->min (), vr_result->max ()) > 0))
     ;
   else
     set_value_range_to_varying (vr_result);
@@ -3071,8 +3018,8 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
       vr = get_value_range (op0);
       if (range_int_cst_p (vr))
 	{
-	  op0min = vr->min;
-	  op0max = vr->max;
+	  op0min = vr->min ();
+	  op0max = vr->max ();
 	}
     }
 
@@ -3081,7 +3028,7 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
     {
       value_range *vr1 = get_value_range (op1);
       if (range_int_cst_p (vr1))
-	op1min = vr1->min;
+	op1min = vr1->min ();
     }
   if (rhs_code == TRUNC_MOD_EXPR
       && TREE_CODE (op1min) == INTEGER_CST
@@ -3285,8 +3232,7 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
   tree op0 = gimple_assign_rhs1 (stmt);
   tree op1 = gimple_assign_rhs2 (stmt);
   tree op = NULL_TREE;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
+  value_range vr0, vr1;
   wide_int may_be_nonzero0, may_be_nonzero1;
   wide_int must_be_nonzero0, must_be_nonzero1;
   wide_int mask;
@@ -3405,10 +3351,10 @@ test_for_singularity (enum tree_code cond_code, tree op0,
      value range information we have for op0.  */
   if (min && max)
     {
-      if (compare_values (vr->min, min) == 1)
-	min = vr->min;
-      if (compare_values (vr->max, max) == -1)
-	max = vr->max;
+      if (compare_values (vr->min (), min) == 1)
+	min = vr->min ();
+      if (compare_values (vr->max (), max) == -1)
+	max = vr->max ();
 
       /* If the new min/max values have converged to a single value,
 	 then there is only one value which can satisfy the condition,
@@ -3431,14 +3377,14 @@ range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
   signop src_sgn;
 
   /* We can only handle integral and pointer types.  */
-  src_type = TREE_TYPE (vr->min);
+  src_type = vr->type ();
   if (!INTEGRAL_TYPE_P (src_type)
       && !POINTER_TYPE_P (src_type))
     return false;
 
   /* An extension is fine unless VR is SIGNED and dest_sgn is UNSIGNED,
      and so is an identity transform.  */
-  src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
+  src_precision = TYPE_PRECISION (vr->type ());
   src_sgn = TYPE_SIGN (src_type);
   if ((src_precision < dest_precision
        && !(dest_sgn == UNSIGNED && src_sgn == SIGNED))
@@ -3446,9 +3392,7 @@ range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
     return true;
 
   /* Now we can only handle ranges with constant bounds.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (!range_int_cst_p (vr))
     return false;
 
   /* For sign changes, the MSB of the wide_int has to be clear.
@@ -3456,17 +3400,17 @@ range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
      a signed wide_int, while a negative value cannot be represented
      by an unsigned wide_int.  */
   if (src_sgn != dest_sgn
-      && (wi::lts_p (wi::to_wide (vr->min), 0)
-	  || wi::lts_p (wi::to_wide (vr->max), 0)))
+      && (wi::lts_p (wi::to_wide (vr->min ()), 0)
+	  || wi::lts_p (wi::to_wide (vr->max ()), 0)))
     return false;
 
   /* Then we can perform the conversion on both ends and compare
      the result for equality.  */
-  tem = wi::ext (wi::to_widest (vr->min), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->min))
+  tem = wi::ext (wi::to_widest (vr->min ()), dest_precision, dest_sgn);
+  if (tem != wi::to_widest (vr->min ()))
     return false;
-  tem = wi::ext (wi::to_widest (vr->max), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->max))
+  tem = wi::ext (wi::to_widest (vr->max ()), dest_precision, dest_sgn);
+  if (tem != wi::to_widest (vr->max ()))
     return false;
 
   return true;
@@ -3493,7 +3437,7 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
 
       /* If we have range information for OP0, then we might be
 	 able to simplify this conditional. */
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  tree new_tree = test_for_singularity (cond_code, op0, op1, vr);
 	  if (new_tree)
@@ -3636,9 +3580,9 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
       vr = get_value_range (op);
 
       /* We can only handle integer ranges.  */
-      if ((vr->type != VR_RANGE
-	   && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->varying_p ()
+	  || vr->undefined_p ()
+	  || vr->symbolic_p ())
 	return false;
 
       /* Find case label for min/max of the value range.  */
@@ -3666,7 +3610,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
      value range.  */
   size_t min_idx = 1, max_idx = 0;
   if (vr != NULL)
-    find_case_label_range (stmt, vr->min, vr->max, &min_idx, &max_idx);
+    find_case_label_range (stmt, vr->min (), vr->max (), &min_idx, &max_idx);
   if (min_idx <= max_idx)
     {
       tree min_label = gimple_switch_label (stmt, min_idx);
@@ -3674,10 +3618,10 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
 
       /* Avoid changing the type of the case labels when truncating.  */
       tree case_label_type = TREE_TYPE (CASE_LOW (min_label));
-      tree vr_min = fold_convert (case_label_type, vr->min);
-      tree vr_max = fold_convert (case_label_type, vr->max);
+      tree vr_min = fold_convert (case_label_type, vr->min ());
+      tree vr_max = fold_convert (case_label_type, vr->max ());
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == VR_RANGE)
 	{
 	  /* If OP's value range is [2,8] and the low label range is
 	     0 ... 3, truncate the label's range to 2 .. 3.  */
@@ -3693,7 +3637,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt)
 	      && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0)
 	    CASE_HIGH (max_label) = vr_max;
 	}
-      else if (vr->type == VR_ANTI_RANGE)
+      else if (vr->kind () == VR_ANTI_RANGE)
 	{
 	  tree one_cst = build_one_cst (case_label_type);
 
@@ -3930,9 +3874,7 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
   gassign *conv;
 
   /* We can only handle constant ranges.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (!range_int_cst_p (vr))
     return false;
 
   /* First check if we can use a signed type in place of an unsigned.  */
@@ -4088,26 +4030,26 @@ bool
 vr_values::two_valued_val_range_p (tree var, tree *a, tree *b)
 {
   value_range *vr = get_value_range (var);
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (vr->varying_p ()
+      || vr->undefined_p ()
+      || TREE_CODE (vr->min ()) != INTEGER_CST
+      || TREE_CODE (vr->max ()) != INTEGER_CST)
     return false;
 
-  if (vr->type == VR_RANGE
-      && wi::to_wide (vr->max) - wi::to_wide (vr->min) == 1)
+  if (vr->kind () == VR_RANGE
+      && wi::to_wide (vr->max ()) - wi::to_wide (vr->min ()) == 1)
     {
-      *a = vr->min;
-      *b = vr->max;
+      *a = vr->min ();
+      *b = vr->max ();
       return true;
     }
 
   /* ~[TYPE_MIN + 1, TYPE_MAX - 1] */
-  if (vr->type == VR_ANTI_RANGE
-      && (wi::to_wide (vr->min)
+  if (vr->kind () == VR_ANTI_RANGE
+      && (wi::to_wide (vr->min ())
 	  - wi::to_wide (vrp_val_min (TREE_TYPE (var)))) == 1
       && (wi::to_wide (vrp_val_max (TREE_TYPE (var)))
-	  - wi::to_wide (vr->max)) == 1)
+	  - wi::to_wide (vr->max ())) == 1)
     {
       *a = vrp_val_min (TREE_TYPE (var));
       *b = vrp_val_max (TREE_TYPE (var));
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 487a800c1ea..496707856c3 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -72,7 +72,7 @@ class vr_values
   void cleanup_edges_and_switches (void);
 
  private:
-  void add_equivalence (bitmap *, const_tree);
+  bitmap add_equivalence (bitmap, const_tree);
   bool vrp_stmt_computes_nonzero (gimple *);
   bool op_with_boolean_value_range_p (tree);
   bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);
@@ -142,7 +142,5 @@ class vr_values
   vec<switch_update> to_update_switch_stmts;
 };
 
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
-
 extern tree get_output_for_vrp (gimple *);
 #endif /* GCC_VR_VALUES_H */
Richard Biener Oct. 17, 2018, 10:50 a.m. | #5
On Thu, Oct 11, 2018 at 8:25 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
>
>
> On 10/11/18 5:47 AM, Richard Biener wrote:
> > On Thu, Oct 11, 2018 at 10:19 AM Aldy Hernandez <aldyh@redhat.com> wrote:
> >>
> >> Hi Richard.  Thanks for reviewing.
> >>
> >> On 10/10/18 6:27 AM, Richard Biener wrote:
> >>> On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
> >>>>
> >>>> I'm assuming the silence on the RFC means nobody is viscerally opposed
> >>>> to it, so here goes the actual implementation ;-).
> >>>>
> >>>>           FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
> >>>>
> >>>> My aim is no change to the current functionality, but there are some
> >>>> things that changed slightly (with no appreciable change in
> >>>> bootstrapability or tests).
> >>>>
> >>>> 1.  Primarily, we were building value_ranges by modifying them in-flight
> >>>> with no regards to the validity of the resulting range.  By enforcing
> >>>> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
> >>>> left the equivalence bits uncleared.  This comment in the original
> >>>> header file indicates that this is invalid behavior:
> >>>>
> >>>>      /* Set of SSA names whose value ranges are equivalent to this one.
> >>>>         This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
> >>>>
> >>>> The API now enforces this upon construction.
> >>>>
> >>>> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
> >>>> This is invalid.  Although these values were being ignored, the API now
> >>>> enforces this.
> >>>>
> >>>> 3. I saw one case in set_value_range_with_overflow() were we were
> >>>> building an invalid range with swapped ranges, where we were silently
> >>>> depending on somebody further up the call chain to swap them for us.
> >>>> I've fixed this at creation.
> >>>>
> >>>> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
> >>>> left as proof that the original VR_UNDEFINED set was not necessary, as
> >>>> it is now done by default on an empty constructor:
> >>>>
> >>>> -  void init () { m_vr.type = VR_UNDEFINED; }
> >>>> +  void init () { gcc_assert (m_vr.undefined_p ()); }
> >>>>
> >>>> One last note.  The file tree-vrp.c already has a cripple API of sorts
> >>>> in the form of functions (set_value_range_to_varying, etc).  I have
> >>>> tried to keep those functions available, by calling the API under the
> >>>> covers, but would be okay in removing them altogether as a follow-up.
> >>>>
> >>>> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
> >>>> new tree type field.
> >>>>
> >>>> I am quoting the class declaration below to make it easy to review at a
> >>>> high level.
> >>>>
> >>>> Tested on x86-64 Linux.  All languages, including Ada and Go.
> >>>>
> >>>> OK for trunk?
> >>>
> >>> Reviewing in patch order.
> >>>
> >>>> Aldy
> >>>>
> >>>> class GTY((for_user)) value_range
> >>>> {
> >>>>     public:
> >>>>      value_range ();
> >>>>      value_range (tree type);
> >>>>      value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
> >>>>      bool operator== (const value_range &) const;
> >>>>      bool operator!= (const value_range &) const;
> >>>>      void intersect (const value_range *);
> >>>>      void union_ (const value_range *);
> >>>
> >>> with trailing underscore?  seriously?
> >>
> >> Hey!  You complained about Union() last year, at which point the
> >> consensus was that trailing underscores would be ok for symbol names
> >> that clashed with keywords.
> >
> > ;)
> >
> > I also thought about union_into / union_with.  As opposed to a hypothetical
> >
> >    value_range union (const value_range& a, const value_range& b)
> >
> > function.
> >
> >> And yes, it was also discussed whether we should overload | and ^ for
> >> union and intersection, but was denied for readability and what have yous.
> >>
> >>>
> >>>>      /* Like operator== but ignore equivalence bitmap.  */
> >>>>      bool ignore_equivs_equal_p (const value_range &) const;
> >>>>      /* Like a operator= but update equivalence bitmap efficiently.  */
> >>>>      void copy_with_equiv_update (const value_range *);
> >>>>
> >>>>      /* Types of value ranges.  */
> >>>>      bool undefined_p () const;
> >>>>      bool varying_p () const;
> >>>>      bool symbolic_p () const;
> >>>>      bool numeric_p () const;
> >>>>      void set_undefined (tree = NULL);
> >>>>      void set_varying (tree = NULL);
> >>>
> >>> I'd appreciate comments on those predicates, esp. as you
> >>> replace positive tests by negative ones like in
> >>
> >> Done.
> >>
> >>>
> >>>      /* If we found any usable VR, set the VR to ssa_name and create a
> >>>         PUSH old value in the stack with the old VR.  */
> >>> -  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> >>> +  if (!vr.undefined_p () && !vr.varying_p ())
> >>>        {
> >>>
> >>> I'd also spell numeric_p as constant_p or drop it alltogether
> >>> since !symbolic_p should imply it given varying_p and undefined_p
> >>> are just some special-cases of "numeric_p" (full and empty range).
> >>
> >> Done.
> >>
> >>>
> >>> That said, for the time being I'd use non_symbolic_range_or_anti_range_p
> >>> instead of numeric_p () (seeing that you maybe want to hide the fact
> >>> that we have anti-ranges?)
> >>
> >> Errr... No.
> >>
> >>>
> >>> -  value_range vr = VR_INITIALIZER;
> >>> +  value_range vr (TREE_TYPE (name));
> >>>
> >>> so you basically forgo with the fact that empty ranges are universal?
> >>> I don't like it too much that we have to invent a type here.  Why enforce this
> >>> and not allow/force type == NULL_TREE for empty ranges?
> >>>
> >>> One could argue VARYING is also universal to some extent and useful
> >>> only with context, so similar argument applies to your change forcing
> >>> a type for set_value_range_to_varying.
> >>>
> >>> -      value_range vr = VR_INITIALIZER;
> >>> +      value_range vr;
> >>>
> >>> oh, so you do have a default constructor.
> >>>
> >>>>
> >>>>      /* Equivalence bitmap methods.  */
> >>>>      bitmap equiv () const;
> >>>>      void set_equiv (bitmap);
> >>>
> >>> Err, I think we've settled on _not_ wrapping all member accesses
> >>> with get/set methods, didn't we?  I personally dislike that very much.
> >>>
> >>>>      void equiv_free ();
> >>>>      void equiv_copy (const value_range *);
> >>>>      void equiv_clear ();
> >>>>      void equiv_and (const value_range *);
> >>>>      void equiv_ior (const value_range *);
> >>>
> >>> Likewise I find this useless abstraction.  It's even questionable
> >>> if _free/_clear/_copy are good APIs here.  This should be all
> >>> hidden in intersect/union which I do not find in the API at all...
> >>
> >> I missed that discussion.  We did?  I dislike exposing the internals.
> >> Abstracting things out makes it easier to change things in the future--
> >> or insert instrumenting code, or whatever.
> >
> > OK, I might misremember and it's eventually just my personal taste
> > against slapping a setFoo/getFoo method in a class as the first
> > thing to do after adding a m_Foo member...
> >
> >> That said, I have removed copy/free/and/or.  As you said, it was much
> >> easier to make the details internal to the intersect/union member functions.
> >>
> >> However, I have kept:
> >>
> >>     bitmap equiv () const;
> >>     void set_equiv (bitmap);
> >>     void equiv_clear ();
> >>
> >> I think we can get away with just having a clear, instead of a free, as
> >> it's all in an obstack and there doesn't seem to be any consistent use
> >> of free vs. clear throughout (except one or two, which I've kept).
> >
> > Yeah.
> >
> >> Also, we don't really need to expose set_equiv(), but for its one use in
> >> vr_values::add_equivalence().  One option could be to make vr_values and
> >> value_ranges friends and let add_equivalence touch m_equiv.  But that's
> >> a bit heavy handed.
> >>
> >> Or we could add this to the API instead of set_equiv():
> >>
> >> void
> >> value_range::add_equivalence (bitmap_obstack obstack, tree var)
> >> {
> >> }
> >>
> >> I don't know how I feel about passing the obtack, or including
> >> "bitmap.h" from everywhere tree-vrp.h is used (that is, everywhere).
> >
> > Equivalences are evil ;)  But I guess passing in the obstack works
> > for me.  Maybe as trailing argument, defaulted to NULL in which
> > case we use the default bitmap obstack?
>
> Done.
>
> >
> >> For equiv(), we could remove virtually all of its uses, since 99% of
> >> them are in the form:
> >>
> >>          set_value_range (vr, VR_SOMETHING, min, max, vr->equiv ())
> >>
> >> Instead we could We could provide:
> >>
> >>          vr->update (VR_SOMETHING, min, max);
> >>
> >> ...which is just like set_value_range, but keeping the equivalences intact.
> >
> > Yep, sounds good.
>
> Done.
>
> >
> >>   > hidden in intersect/union which I do not find in the API at all...
> >>
> >> How could you, it was front and center ;-):
> >>
> >>     void intersect (const value_range *);
> >>     void union_ (const value_range *);
> >
> > Missed that in the first review and then failed to delete that comment ;)
> >
> >>>
> >>>>
> >>>>      /* Misc methods.  */
> >>>>      tree type () const;
> >>>
> >>> type() and vrtype() is confusing - value_type() and range_kind() maybe?
> >>
> >> How about we keep type(), since 99% of all uses of "type" in the
> >> compiler are "tree type", so it's easy to figure out.  And instead of
> >> range_kind() we use kind().  It's already obvious it's a range, so
> >> vr->kind() reads fine IMO.
> >
> > Works for me.
>
> Done.
>
> >
> >>>
> >>>>      bool null_p () const;
> >>>>      bool may_contain_p (tree) const;
> >>>>      tree singleton () const;
> >>>
> >>> No documentation? :/   Why null_p but singleton (instead of singleton_p)?
> >>
> >> Documented.
> >>
> >> Singleton returns the singleton if found, otherwise returns NULL.
> >> NULL_P returns true/or false.  I thought the preferred way was for _p to
> >> always return booleans.
> >
> > Ah, missed that "detail"...
> >
> >> I don't feel strongly, so I've renamed it to singleton_p() since a
> >> NULL_TREE is as good as false.  Another option is:
> >>
> >>          bool singleton_p (tree *result = NULL)
> >>
> >> Hmmm...I like this last one.  What do you think?
> >
> > Like it as well.
>
> Done.
>
> >
> >>>
> >>>>      void set_and_canonicalize (enum value_range_type, tree, tree, tree,
> >>>> bitmap);
> >>>
> >>> Why's that necessary if you enforce sanity?
> >>
> >> Canonicalize also does some optimizations like converting anti-ranges
> >> into ranges if possible.  Although I would be OK with putting that
> >> functionality in value_range::set() to be done on creation, I don't know
> >> how I feel about polluting the creation code with fixing swapped min/max:
> >>
> >>     /* Wrong order for min and max, to swap them and the VR type we need
> >>        to adjust them.  */
> >>
> >> It feels wrong to construct a range with swapped end-points, and hope
> >> things turn out ok.  ISTM that canonicalize() clearly specifies intent:
> >> I'm giving you a shitty range, fix it.
> >>
> >> Thoughts?
> >
> > OK, let's keep it the way you had it.  I never liked this part very much
> > (even though I added it!).
>
> Sounds like you need to have a long talk with yourself ;-).
>
> >
> >>>
> >>>>      void dump () const;
> >>>>
> >>>>      /* Temporary accessors that should eventually be removed.  */
> >>>>      enum value_range_type vrtype () const;
> >>>>      tree min () const;
> >>>>      tree max () const;
> >>>>
> >>>>     private:
> >>>>      void set (value_range_type, tree type, tree, tree, bitmap);
> >>>>      void check ();
> >>>>      bool equal_p (const value_range &, bool ignore_equivs) const;
> >>>>
> >>>>      enum value_range_type m_vrtype;
> >>>>     public:
> >>>>      /* These should be private, but GTY is a piece of crap.  */
> >>>>      tree m_min;
> >>>>      tree m_max;
> >>>>      tree m_type;
> >>>
> >>> m_type is redundant (see above).
> >>
> >> Removed.
> >>
> >> Tested on x86-64 Linux.
> >>
> >> Aldy
> >>
> >> p.s. Oh yeah, it wouldn't be an Aldy patch without an irrelevant bit
> >> added for good measure:
> >>
> >> +void
> >> +bitmap_head::dump ()
> >> +{
> >> +  debug (this);
> >> +}
> >>
> >> I find having ->dump() available for each and every structure in GCC
> >> helpful in debugging.  At some point we should standardize on dump(FILE
> >> *) and debug() to dump to stderr.  But alas, there are too many dump()'s
> >> that already dump to stderr :-/.
> >
> > FWIW I like
> >
> > void dump (const bitmap_head&);
> >
> > more since it doesn't clutter the APIs and can theoretically be very
> > easily not built into a release compiler.  And IIRC we already have
> > global overloads of debug () for exactly the reason you cite.  Having
> > both styles is IMHO not good.  (and I've stated my preference - feel
> > free to provide statistics for in-tree uses ;))
>
> Ughh, maybe in the future I'll sit down and convert everything to
> something regular.
>
> Tested with all languages on x86-64 Linux.
>
> OK for trunk?

You seem to remove vr_values::add_equivalence but then...

diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 487a800c1ea..496707856c3 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -72,7 +72,7 @@ class vr_values
   void cleanup_edges_and_switches (void);

  private:
-  void add_equivalence (bitmap *, const_tree);
+  bitmap add_equivalence (bitmap, const_tree);
   bool vrp_stmt_computes_nonzero (gimple *);
   bool op_with_boolean_value_range_p (tree);
   bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);

so please remove the method in the class as well.

OK with that change.
Richard.

> Aldy
Aldy Hernandez Oct. 17, 2018, 2:39 p.m. | #6
On 10/17/18 6:50 AM, Richard Biener wrote:
> On Thu, Oct 11, 2018 at 8:25 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>
>>
>>
>> On 10/11/18 5:47 AM, Richard Biener wrote:
>>> On Thu, Oct 11, 2018 at 10:19 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>>>>
>>>> Hi Richard.  Thanks for reviewing.
>>>>
>>>> On 10/10/18 6:27 AM, Richard Biener wrote:
>>>>> On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>>>>>>
>>>>>> I'm assuming the silence on the RFC means nobody is viscerally opposed
>>>>>> to it, so here goes the actual implementation ;-).
>>>>>>
>>>>>>            FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
>>>>>>
>>>>>> My aim is no change to the current functionality, but there are some
>>>>>> things that changed slightly (with no appreciable change in
>>>>>> bootstrapability or tests).
>>>>>>
>>>>>> 1.  Primarily, we were building value_ranges by modifying them in-flight
>>>>>> with no regards to the validity of the resulting range.  By enforcing
>>>>>> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
>>>>>> left the equivalence bits uncleared.  This comment in the original
>>>>>> header file indicates that this is invalid behavior:
>>>>>>
>>>>>>       /* Set of SSA names whose value ranges are equivalent to this one.
>>>>>>          This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
>>>>>>
>>>>>> The API now enforces this upon construction.
>>>>>>
>>>>>> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
>>>>>> This is invalid.  Although these values were being ignored, the API now
>>>>>> enforces this.
>>>>>>
>>>>>> 3. I saw one case in set_value_range_with_overflow() were we were
>>>>>> building an invalid range with swapped ranges, where we were silently
>>>>>> depending on somebody further up the call chain to swap them for us.
>>>>>> I've fixed this at creation.
>>>>>>
>>>>>> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
>>>>>> left as proof that the original VR_UNDEFINED set was not necessary, as
>>>>>> it is now done by default on an empty constructor:
>>>>>>
>>>>>> -  void init () { m_vr.type = VR_UNDEFINED; }
>>>>>> +  void init () { gcc_assert (m_vr.undefined_p ()); }
>>>>>>
>>>>>> One last note.  The file tree-vrp.c already has a cripple API of sorts
>>>>>> in the form of functions (set_value_range_to_varying, etc).  I have
>>>>>> tried to keep those functions available, by calling the API under the
>>>>>> covers, but would be okay in removing them altogether as a follow-up.
>>>>>>
>>>>>> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
>>>>>> new tree type field.
>>>>>>
>>>>>> I am quoting the class declaration below to make it easy to review at a
>>>>>> high level.
>>>>>>
>>>>>> Tested on x86-64 Linux.  All languages, including Ada and Go.
>>>>>>
>>>>>> OK for trunk?
>>>>>
>>>>> Reviewing in patch order.
>>>>>
>>>>>> Aldy
>>>>>>
>>>>>> class GTY((for_user)) value_range
>>>>>> {
>>>>>>      public:
>>>>>>       value_range ();
>>>>>>       value_range (tree type);
>>>>>>       value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
>>>>>>       bool operator== (const value_range &) const;
>>>>>>       bool operator!= (const value_range &) const;
>>>>>>       void intersect (const value_range *);
>>>>>>       void union_ (const value_range *);
>>>>>
>>>>> with trailing underscore?  seriously?
>>>>
>>>> Hey!  You complained about Union() last year, at which point the
>>>> consensus was that trailing underscores would be ok for symbol names
>>>> that clashed with keywords.
>>>
>>> ;)
>>>
>>> I also thought about union_into / union_with.  As opposed to a hypothetical
>>>
>>>     value_range union (const value_range& a, const value_range& b)
>>>
>>> function.
>>>
>>>> And yes, it was also discussed whether we should overload | and ^ for
>>>> union and intersection, but was denied for readability and what have yous.
>>>>
>>>>>
>>>>>>       /* Like operator== but ignore equivalence bitmap.  */
>>>>>>       bool ignore_equivs_equal_p (const value_range &) const;
>>>>>>       /* Like a operator= but update equivalence bitmap efficiently.  */
>>>>>>       void copy_with_equiv_update (const value_range *);
>>>>>>
>>>>>>       /* Types of value ranges.  */
>>>>>>       bool undefined_p () const;
>>>>>>       bool varying_p () const;
>>>>>>       bool symbolic_p () const;
>>>>>>       bool numeric_p () const;
>>>>>>       void set_undefined (tree = NULL);
>>>>>>       void set_varying (tree = NULL);
>>>>>
>>>>> I'd appreciate comments on those predicates, esp. as you
>>>>> replace positive tests by negative ones like in
>>>>
>>>> Done.
>>>>
>>>>>
>>>>>       /* If we found any usable VR, set the VR to ssa_name and create a
>>>>>          PUSH old value in the stack with the old VR.  */
>>>>> -  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
>>>>> +  if (!vr.undefined_p () && !vr.varying_p ())
>>>>>         {
>>>>>
>>>>> I'd also spell numeric_p as constant_p or drop it alltogether
>>>>> since !symbolic_p should imply it given varying_p and undefined_p
>>>>> are just some special-cases of "numeric_p" (full and empty range).
>>>>
>>>> Done.
>>>>
>>>>>
>>>>> That said, for the time being I'd use non_symbolic_range_or_anti_range_p
>>>>> instead of numeric_p () (seeing that you maybe want to hide the fact
>>>>> that we have anti-ranges?)
>>>>
>>>> Errr... No.
>>>>
>>>>>
>>>>> -  value_range vr = VR_INITIALIZER;
>>>>> +  value_range vr (TREE_TYPE (name));
>>>>>
>>>>> so you basically forgo with the fact that empty ranges are universal?
>>>>> I don't like it too much that we have to invent a type here.  Why enforce this
>>>>> and not allow/force type == NULL_TREE for empty ranges?
>>>>>
>>>>> One could argue VARYING is also universal to some extent and useful
>>>>> only with context, so similar argument applies to your change forcing
>>>>> a type for set_value_range_to_varying.
>>>>>
>>>>> -      value_range vr = VR_INITIALIZER;
>>>>> +      value_range vr;
>>>>>
>>>>> oh, so you do have a default constructor.
>>>>>
>>>>>>
>>>>>>       /* Equivalence bitmap methods.  */
>>>>>>       bitmap equiv () const;
>>>>>>       void set_equiv (bitmap);
>>>>>
>>>>> Err, I think we've settled on _not_ wrapping all member accesses
>>>>> with get/set methods, didn't we?  I personally dislike that very much.
>>>>>
>>>>>>       void equiv_free ();
>>>>>>       void equiv_copy (const value_range *);
>>>>>>       void equiv_clear ();
>>>>>>       void equiv_and (const value_range *);
>>>>>>       void equiv_ior (const value_range *);
>>>>>
>>>>> Likewise I find this useless abstraction.  It's even questionable
>>>>> if _free/_clear/_copy are good APIs here.  This should be all
>>>>> hidden in intersect/union which I do not find in the API at all...
>>>>
>>>> I missed that discussion.  We did?  I dislike exposing the internals.
>>>> Abstracting things out makes it easier to change things in the future--
>>>> or insert instrumenting code, or whatever.
>>>
>>> OK, I might misremember and it's eventually just my personal taste
>>> against slapping a setFoo/getFoo method in a class as the first
>>> thing to do after adding a m_Foo member...
>>>
>>>> That said, I have removed copy/free/and/or.  As you said, it was much
>>>> easier to make the details internal to the intersect/union member functions.
>>>>
>>>> However, I have kept:
>>>>
>>>>      bitmap equiv () const;
>>>>      void set_equiv (bitmap);
>>>>      void equiv_clear ();
>>>>
>>>> I think we can get away with just having a clear, instead of a free, as
>>>> it's all in an obstack and there doesn't seem to be any consistent use
>>>> of free vs. clear throughout (except one or two, which I've kept).
>>>
>>> Yeah.
>>>
>>>> Also, we don't really need to expose set_equiv(), but for its one use in
>>>> vr_values::add_equivalence().  One option could be to make vr_values and
>>>> value_ranges friends and let add_equivalence touch m_equiv.  But that's
>>>> a bit heavy handed.
>>>>
>>>> Or we could add this to the API instead of set_equiv():
>>>>
>>>> void
>>>> value_range::add_equivalence (bitmap_obstack obstack, tree var)
>>>> {
>>>> }
>>>>
>>>> I don't know how I feel about passing the obtack, or including
>>>> "bitmap.h" from everywhere tree-vrp.h is used (that is, everywhere).
>>>
>>> Equivalences are evil ;)  But I guess passing in the obstack works
>>> for me.  Maybe as trailing argument, defaulted to NULL in which
>>> case we use the default bitmap obstack?
>>
>> Done.
>>
>>>
>>>> For equiv(), we could remove virtually all of its uses, since 99% of
>>>> them are in the form:
>>>>
>>>>           set_value_range (vr, VR_SOMETHING, min, max, vr->equiv ())
>>>>
>>>> Instead we could We could provide:
>>>>
>>>>           vr->update (VR_SOMETHING, min, max);
>>>>
>>>> ...which is just like set_value_range, but keeping the equivalences intact.
>>>
>>> Yep, sounds good.
>>
>> Done.
>>
>>>
>>>>    > hidden in intersect/union which I do not find in the API at all...
>>>>
>>>> How could you, it was front and center ;-):
>>>>
>>>>      void intersect (const value_range *);
>>>>      void union_ (const value_range *);
>>>
>>> Missed that in the first review and then failed to delete that comment ;)
>>>
>>>>>
>>>>>>
>>>>>>       /* Misc methods.  */
>>>>>>       tree type () const;
>>>>>
>>>>> type() and vrtype() is confusing - value_type() and range_kind() maybe?
>>>>
>>>> How about we keep type(), since 99% of all uses of "type" in the
>>>> compiler are "tree type", so it's easy to figure out.  And instead of
>>>> range_kind() we use kind().  It's already obvious it's a range, so
>>>> vr->kind() reads fine IMO.
>>>
>>> Works for me.
>>
>> Done.
>>
>>>
>>>>>
>>>>>>       bool null_p () const;
>>>>>>       bool may_contain_p (tree) const;
>>>>>>       tree singleton () const;
>>>>>
>>>>> No documentation? :/   Why null_p but singleton (instead of singleton_p)?
>>>>
>>>> Documented.
>>>>
>>>> Singleton returns the singleton if found, otherwise returns NULL.
>>>> NULL_P returns true/or false.  I thought the preferred way was for _p to
>>>> always return booleans.
>>>
>>> Ah, missed that "detail"...
>>>
>>>> I don't feel strongly, so I've renamed it to singleton_p() since a
>>>> NULL_TREE is as good as false.  Another option is:
>>>>
>>>>           bool singleton_p (tree *result = NULL)
>>>>
>>>> Hmmm...I like this last one.  What do you think?
>>>
>>> Like it as well.
>>
>> Done.
>>
>>>
>>>>>
>>>>>>       void set_and_canonicalize (enum value_range_type, tree, tree, tree,
>>>>>> bitmap);
>>>>>
>>>>> Why's that necessary if you enforce sanity?
>>>>
>>>> Canonicalize also does some optimizations like converting anti-ranges
>>>> into ranges if possible.  Although I would be OK with putting that
>>>> functionality in value_range::set() to be done on creation, I don't know
>>>> how I feel about polluting the creation code with fixing swapped min/max:
>>>>
>>>>      /* Wrong order for min and max, to swap them and the VR type we need
>>>>         to adjust them.  */
>>>>
>>>> It feels wrong to construct a range with swapped end-points, and hope
>>>> things turn out ok.  ISTM that canonicalize() clearly specifies intent:
>>>> I'm giving you a shitty range, fix it.
>>>>
>>>> Thoughts?
>>>
>>> OK, let's keep it the way you had it.  I never liked this part very much
>>> (even though I added it!).
>>
>> Sounds like you need to have a long talk with yourself ;-).
>>
>>>
>>>>>
>>>>>>       void dump () const;
>>>>>>
>>>>>>       /* Temporary accessors that should eventually be removed.  */
>>>>>>       enum value_range_type vrtype () const;
>>>>>>       tree min () const;
>>>>>>       tree max () const;
>>>>>>
>>>>>>      private:
>>>>>>       void set (value_range_type, tree type, tree, tree, bitmap);
>>>>>>       void check ();
>>>>>>       bool equal_p (const value_range &, bool ignore_equivs) const;
>>>>>>
>>>>>>       enum value_range_type m_vrtype;
>>>>>>      public:
>>>>>>       /* These should be private, but GTY is a piece of crap.  */
>>>>>>       tree m_min;
>>>>>>       tree m_max;
>>>>>>       tree m_type;
>>>>>
>>>>> m_type is redundant (see above).
>>>>
>>>> Removed.
>>>>
>>>> Tested on x86-64 Linux.
>>>>
>>>> Aldy
>>>>
>>>> p.s. Oh yeah, it wouldn't be an Aldy patch without an irrelevant bit
>>>> added for good measure:
>>>>
>>>> +void
>>>> +bitmap_head::dump ()
>>>> +{
>>>> +  debug (this);
>>>> +}
>>>>
>>>> I find having ->dump() available for each and every structure in GCC
>>>> helpful in debugging.  At some point we should standardize on dump(FILE
>>>> *) and debug() to dump to stderr.  But alas, there are too many dump()'s
>>>> that already dump to stderr :-/.
>>>
>>> FWIW I like
>>>
>>> void dump (const bitmap_head&);
>>>
>>> more since it doesn't clutter the APIs and can theoretically be very
>>> easily not built into a release compiler.  And IIRC we already have
>>> global overloads of debug () for exactly the reason you cite.  Having
>>> both styles is IMHO not good.  (and I've stated my preference - feel
>>> free to provide statistics for in-tree uses ;))
>>
>> Ughh, maybe in the future I'll sit down and convert everything to
>> something regular.
>>
>> Tested with all languages on x86-64 Linux.
>>
>> OK for trunk?
> 
> You seem to remove vr_values::add_equivalence but then...
> 
> diff --git a/gcc/vr-values.h b/gcc/vr-values.h
> index 487a800c1ea..496707856c3 100644
> --- a/gcc/vr-values.h
> +++ b/gcc/vr-values.h
> @@ -72,7 +72,7 @@ class vr_values
>     void cleanup_edges_and_switches (void);
> 
>    private:
> -  void add_equivalence (bitmap *, const_tree);
> +  bitmap add_equivalence (bitmap, const_tree);
>     bool vrp_stmt_computes_nonzero (gimple *);
>     bool op_with_boolean_value_range_p (tree);
>     bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);
> 
> so please remove the method in the class as well.
> 
> OK with that change.

I am updating my tree and will commit once a sanity bootstrap succeeds.

Thanks so much for your review.

Aldy
H.J. Lu Oct. 21, 2018, 1:33 a.m. | #7
On Wed, Oct 17, 2018 at 7:39 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>
>
>
> On 10/17/18 6:50 AM, Richard Biener wrote:
> > On Thu, Oct 11, 2018 at 8:25 PM Aldy Hernandez <aldyh@redhat.com> wrote:
> >>
> >>
> >>
> >> On 10/11/18 5:47 AM, Richard Biener wrote:
> >>> On Thu, Oct 11, 2018 at 10:19 AM Aldy Hernandez <aldyh@redhat.com> wrote:
> >>>>
> >>>> Hi Richard.  Thanks for reviewing.
> >>>>
> >>>> On 10/10/18 6:27 AM, Richard Biener wrote:
> >>>>> On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
> >>>>>>
> >>>>>> I'm assuming the silence on the RFC means nobody is viscerally opposed
> >>>>>> to it, so here goes the actual implementation ;-).
> >>>>>>
> >>>>>>            FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
> >>>>>>
> >>>>>> My aim is no change to the current functionality, but there are some
> >>>>>> things that changed slightly (with no appreciable change in
> >>>>>> bootstrapability or tests).
> >>>>>>
> >>>>>> 1.  Primarily, we were building value_ranges by modifying them in-flight
> >>>>>> with no regards to the validity of the resulting range.  By enforcing
> >>>>>> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
> >>>>>> left the equivalence bits uncleared.  This comment in the original
> >>>>>> header file indicates that this is invalid behavior:
> >>>>>>
> >>>>>>       /* Set of SSA names whose value ranges are equivalent to this one.
> >>>>>>          This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
> >>>>>>
> >>>>>> The API now enforces this upon construction.
> >>>>>>
> >>>>>> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
> >>>>>> This is invalid.  Although these values were being ignored, the API now
> >>>>>> enforces this.
> >>>>>>
> >>>>>> 3. I saw one case in set_value_range_with_overflow() were we were
> >>>>>> building an invalid range with swapped ranges, where we were silently
> >>>>>> depending on somebody further up the call chain to swap them for us.
> >>>>>> I've fixed this at creation.
> >>>>>>
> >>>>>> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
> >>>>>> left as proof that the original VR_UNDEFINED set was not necessary, as
> >>>>>> it is now done by default on an empty constructor:
> >>>>>>
> >>>>>> -  void init () { m_vr.type = VR_UNDEFINED; }
> >>>>>> +  void init () { gcc_assert (m_vr.undefined_p ()); }
> >>>>>>
> >>>>>> One last note.  The file tree-vrp.c already has a cripple API of sorts
> >>>>>> in the form of functions (set_value_range_to_varying, etc).  I have
> >>>>>> tried to keep those functions available, by calling the API under the
> >>>>>> covers, but would be okay in removing them altogether as a follow-up.
> >>>>>>
> >>>>>> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
> >>>>>> new tree type field.
> >>>>>>
> >>>>>> I am quoting the class declaration below to make it easy to review at a
> >>>>>> high level.
> >>>>>>
> >>>>>> Tested on x86-64 Linux.  All languages, including Ada and Go.
> >>>>>>
> >>>>>> OK for trunk?
> >>>>>
> >>>>> Reviewing in patch order.
> >>>>>
> >>>>>> Aldy
> >>>>>>
> >>>>>> class GTY((for_user)) value_range
> >>>>>> {
> >>>>>>      public:
> >>>>>>       value_range ();
> >>>>>>       value_range (tree type);
> >>>>>>       value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
> >>>>>>       bool operator== (const value_range &) const;
> >>>>>>       bool operator!= (const value_range &) const;
> >>>>>>       void intersect (const value_range *);
> >>>>>>       void union_ (const value_range *);
> >>>>>
> >>>>> with trailing underscore?  seriously?
> >>>>
> >>>> Hey!  You complained about Union() last year, at which point the
> >>>> consensus was that trailing underscores would be ok for symbol names
> >>>> that clashed with keywords.
> >>>
> >>> ;)
> >>>
> >>> I also thought about union_into / union_with.  As opposed to a hypothetical
> >>>
> >>>     value_range union (const value_range& a, const value_range& b)
> >>>
> >>> function.
> >>>
> >>>> And yes, it was also discussed whether we should overload | and ^ for
> >>>> union and intersection, but was denied for readability and what have yous.
> >>>>
> >>>>>
> >>>>>>       /* Like operator== but ignore equivalence bitmap.  */
> >>>>>>       bool ignore_equivs_equal_p (const value_range &) const;
> >>>>>>       /* Like a operator= but update equivalence bitmap efficiently.  */
> >>>>>>       void copy_with_equiv_update (const value_range *);
> >>>>>>
> >>>>>>       /* Types of value ranges.  */
> >>>>>>       bool undefined_p () const;
> >>>>>>       bool varying_p () const;
> >>>>>>       bool symbolic_p () const;
> >>>>>>       bool numeric_p () const;
> >>>>>>       void set_undefined (tree = NULL);
> >>>>>>       void set_varying (tree = NULL);
> >>>>>
> >>>>> I'd appreciate comments on those predicates, esp. as you
> >>>>> replace positive tests by negative ones like in
> >>>>
> >>>> Done.
> >>>>
> >>>>>
> >>>>>       /* If we found any usable VR, set the VR to ssa_name and create a
> >>>>>          PUSH old value in the stack with the old VR.  */
> >>>>> -  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> >>>>> +  if (!vr.undefined_p () && !vr.varying_p ())
> >>>>>         {
> >>>>>
> >>>>> I'd also spell numeric_p as constant_p or drop it alltogether
> >>>>> since !symbolic_p should imply it given varying_p and undefined_p
> >>>>> are just some special-cases of "numeric_p" (full and empty range).
> >>>>
> >>>> Done.
> >>>>
> >>>>>
> >>>>> That said, for the time being I'd use non_symbolic_range_or_anti_range_p
> >>>>> instead of numeric_p () (seeing that you maybe want to hide the fact
> >>>>> that we have anti-ranges?)
> >>>>
> >>>> Errr... No.
> >>>>
> >>>>>
> >>>>> -  value_range vr = VR_INITIALIZER;
> >>>>> +  value_range vr (TREE_TYPE (name));
> >>>>>
> >>>>> so you basically forgo with the fact that empty ranges are universal?
> >>>>> I don't like it too much that we have to invent a type here.  Why enforce this
> >>>>> and not allow/force type == NULL_TREE for empty ranges?
> >>>>>
> >>>>> One could argue VARYING is also universal to some extent and useful
> >>>>> only with context, so similar argument applies to your change forcing
> >>>>> a type for set_value_range_to_varying.
> >>>>>
> >>>>> -      value_range vr = VR_INITIALIZER;
> >>>>> +      value_range vr;
> >>>>>
> >>>>> oh, so you do have a default constructor.
> >>>>>
> >>>>>>
> >>>>>>       /* Equivalence bitmap methods.  */
> >>>>>>       bitmap equiv () const;
> >>>>>>       void set_equiv (bitmap);
> >>>>>
> >>>>> Err, I think we've settled on _not_ wrapping all member accesses
> >>>>> with get/set methods, didn't we?  I personally dislike that very much.
> >>>>>
> >>>>>>       void equiv_free ();
> >>>>>>       void equiv_copy (const value_range *);
> >>>>>>       void equiv_clear ();
> >>>>>>       void equiv_and (const value_range *);
> >>>>>>       void equiv_ior (const value_range *);
> >>>>>
> >>>>> Likewise I find this useless abstraction.  It's even questionable
> >>>>> if _free/_clear/_copy are good APIs here.  This should be all
> >>>>> hidden in intersect/union which I do not find in the API at all...
> >>>>
> >>>> I missed that discussion.  We did?  I dislike exposing the internals.
> >>>> Abstracting things out makes it easier to change things in the future--
> >>>> or insert instrumenting code, or whatever.
> >>>
> >>> OK, I might misremember and it's eventually just my personal taste
> >>> against slapping a setFoo/getFoo method in a class as the first
> >>> thing to do after adding a m_Foo member...
> >>>
> >>>> That said, I have removed copy/free/and/or.  As you said, it was much
> >>>> easier to make the details internal to the intersect/union member functions.
> >>>>
> >>>> However, I have kept:
> >>>>
> >>>>      bitmap equiv () const;
> >>>>      void set_equiv (bitmap);
> >>>>      void equiv_clear ();
> >>>>
> >>>> I think we can get away with just having a clear, instead of a free, as
> >>>> it's all in an obstack and there doesn't seem to be any consistent use
> >>>> of free vs. clear throughout (except one or two, which I've kept).
> >>>
> >>> Yeah.
> >>>
> >>>> Also, we don't really need to expose set_equiv(), but for its one use in
> >>>> vr_values::add_equivalence().  One option could be to make vr_values and
> >>>> value_ranges friends and let add_equivalence touch m_equiv.  But that's
> >>>> a bit heavy handed.
> >>>>
> >>>> Or we could add this to the API instead of set_equiv():
> >>>>
> >>>> void
> >>>> value_range::add_equivalence (bitmap_obstack obstack, tree var)
> >>>> {
> >>>> }
> >>>>
> >>>> I don't know how I feel about passing the obtack, or including
> >>>> "bitmap.h" from everywhere tree-vrp.h is used (that is, everywhere).
> >>>
> >>> Equivalences are evil ;)  But I guess passing in the obstack works
> >>> for me.  Maybe as trailing argument, defaulted to NULL in which
> >>> case we use the default bitmap obstack?
> >>
> >> Done.
> >>
> >>>
> >>>> For equiv(), we could remove virtually all of its uses, since 99% of
> >>>> them are in the form:
> >>>>
> >>>>           set_value_range (vr, VR_SOMETHING, min, max, vr->equiv ())
> >>>>
> >>>> Instead we could We could provide:
> >>>>
> >>>>           vr->update (VR_SOMETHING, min, max);
> >>>>
> >>>> ...which is just like set_value_range, but keeping the equivalences intact.
> >>>
> >>> Yep, sounds good.
> >>
> >> Done.
> >>
> >>>
> >>>>    > hidden in intersect/union which I do not find in the API at all...
> >>>>
> >>>> How could you, it was front and center ;-):
> >>>>
> >>>>      void intersect (const value_range *);
> >>>>      void union_ (const value_range *);
> >>>
> >>> Missed that in the first review and then failed to delete that comment ;)
> >>>
> >>>>>
> >>>>>>
> >>>>>>       /* Misc methods.  */
> >>>>>>       tree type () const;
> >>>>>
> >>>>> type() and vrtype() is confusing - value_type() and range_kind() maybe?
> >>>>
> >>>> How about we keep type(), since 99% of all uses of "type" in the
> >>>> compiler are "tree type", so it's easy to figure out.  And instead of
> >>>> range_kind() we use kind().  It's already obvious it's a range, so
> >>>> vr->kind() reads fine IMO.
> >>>
> >>> Works for me.
> >>
> >> Done.
> >>
> >>>
> >>>>>
> >>>>>>       bool null_p () const;
> >>>>>>       bool may_contain_p (tree) const;
> >>>>>>       tree singleton () const;
> >>>>>
> >>>>> No documentation? :/   Why null_p but singleton (instead of singleton_p)?
> >>>>
> >>>> Documented.
> >>>>
> >>>> Singleton returns the singleton if found, otherwise returns NULL.
> >>>> NULL_P returns true/or false.  I thought the preferred way was for _p to
> >>>> always return booleans.
> >>>
> >>> Ah, missed that "detail"...
> >>>
> >>>> I don't feel strongly, so I've renamed it to singleton_p() since a
> >>>> NULL_TREE is as good as false.  Another option is:
> >>>>
> >>>>           bool singleton_p (tree *result = NULL)
> >>>>
> >>>> Hmmm...I like this last one.  What do you think?
> >>>
> >>> Like it as well.
> >>
> >> Done.
> >>
> >>>
> >>>>>
> >>>>>>       void set_and_canonicalize (enum value_range_type, tree, tree, tree,
> >>>>>> bitmap);
> >>>>>
> >>>>> Why's that necessary if you enforce sanity?
> >>>>
> >>>> Canonicalize also does some optimizations like converting anti-ranges
> >>>> into ranges if possible.  Although I would be OK with putting that
> >>>> functionality in value_range::set() to be done on creation, I don't know
> >>>> how I feel about polluting the creation code with fixing swapped min/max:
> >>>>
> >>>>      /* Wrong order for min and max, to swap them and the VR type we need
> >>>>         to adjust them.  */
> >>>>
> >>>> It feels wrong to construct a range with swapped end-points, and hope
> >>>> things turn out ok.  ISTM that canonicalize() clearly specifies intent:
> >>>> I'm giving you a shitty range, fix it.
> >>>>
> >>>> Thoughts?
> >>>
> >>> OK, let's keep it the way you had it.  I never liked this part very much
> >>> (even though I added it!).
> >>
> >> Sounds like you need to have a long talk with yourself ;-).
> >>
> >>>
> >>>>>
> >>>>>>       void dump () const;
> >>>>>>
> >>>>>>       /* Temporary accessors that should eventually be removed.  */
> >>>>>>       enum value_range_type vrtype () const;
> >>>>>>       tree min () const;
> >>>>>>       tree max () const;
> >>>>>>
> >>>>>>      private:
> >>>>>>       void set (value_range_type, tree type, tree, tree, bitmap);
> >>>>>>       void check ();
> >>>>>>       bool equal_p (const value_range &, bool ignore_equivs) const;
> >>>>>>
> >>>>>>       enum value_range_type m_vrtype;
> >>>>>>      public:
> >>>>>>       /* These should be private, but GTY is a piece of crap.  */
> >>>>>>       tree m_min;
> >>>>>>       tree m_max;
> >>>>>>       tree m_type;
> >>>>>
> >>>>> m_type is redundant (see above).
> >>>>
> >>>> Removed.
> >>>>
> >>>> Tested on x86-64 Linux.
> >>>>
> >>>> Aldy
> >>>>
> >>>> p.s. Oh yeah, it wouldn't be an Aldy patch without an irrelevant bit
> >>>> added for good measure:
> >>>>
> >>>> +void
> >>>> +bitmap_head::dump ()
> >>>> +{
> >>>> +  debug (this);
> >>>> +}
> >>>>
> >>>> I find having ->dump() available for each and every structure in GCC
> >>>> helpful in debugging.  At some point we should standardize on dump(FILE
> >>>> *) and debug() to dump to stderr.  But alas, there are too many dump()'s
> >>>> that already dump to stderr :-/.
> >>>
> >>> FWIW I like
> >>>
> >>> void dump (const bitmap_head&);
> >>>
> >>> more since it doesn't clutter the APIs and can theoretically be very
> >>> easily not built into a release compiler.  And IIRC we already have
> >>> global overloads of debug () for exactly the reason you cite.  Having
> >>> both styles is IMHO not good.  (and I've stated my preference - feel
> >>> free to provide statistics for in-tree uses ;))
> >>
> >> Ughh, maybe in the future I'll sit down and convert everything to
> >> something regular.
> >>
> >> Tested with all languages on x86-64 Linux.
> >>
> >> OK for trunk?
> >
> > You seem to remove vr_values::add_equivalence but then...
> >
> > diff --git a/gcc/vr-values.h b/gcc/vr-values.h
> > index 487a800c1ea..496707856c3 100644
> > --- a/gcc/vr-values.h
> > +++ b/gcc/vr-values.h
> > @@ -72,7 +72,7 @@ class vr_values
> >     void cleanup_edges_and_switches (void);
> >
> >    private:
> > -  void add_equivalence (bitmap *, const_tree);
> > +  bitmap add_equivalence (bitmap, const_tree);
> >     bool vrp_stmt_computes_nonzero (gimple *);
> >     bool op_with_boolean_value_range_p (tree);
> >     bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);
> >
> > so please remove the method in the class as well.
> >
> > OK with that change.
>
> I am updating my tree and will commit once a sanity bootstrap succeeds.
>
> Thanks so much for your review.
>
> Aldy

This caused:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87670
Aldy Hernandez Oct. 21, 2018, 2:39 p.m. | #8
Is this fixed by Richard's patch to 87640?  if so, perhaps this is a
duplicate of said PR.
On Sun, Oct 21, 2018 at 3:34 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Wed, Oct 17, 2018 at 7:39 AM Aldy Hernandez <aldyh@redhat.com> wrote:
> >
> >
> >
> > On 10/17/18 6:50 AM, Richard Biener wrote:
> > > On Thu, Oct 11, 2018 at 8:25 PM Aldy Hernandez <aldyh@redhat.com> wrote:
> > >>
> > >>
> > >>
> > >> On 10/11/18 5:47 AM, Richard Biener wrote:
> > >>> On Thu, Oct 11, 2018 at 10:19 AM Aldy Hernandez <aldyh@redhat.com> wrote:
> > >>>>
> > >>>> Hi Richard.  Thanks for reviewing.
> > >>>>
> > >>>> On 10/10/18 6:27 AM, Richard Biener wrote:
> > >>>>> On Tue, Oct 9, 2018 at 6:23 PM Aldy Hernandez <aldyh@redhat.com> wrote:
> > >>>>>>
> > >>>>>> I'm assuming the silence on the RFC means nobody is viscerally opposed
> > >>>>>> to it, so here goes the actual implementation ;-).
> > >>>>>>
> > >>>>>>            FWI: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00157.html
> > >>>>>>
> > >>>>>> My aim is no change to the current functionality, but there are some
> > >>>>>> things that changed slightly (with no appreciable change in
> > >>>>>> bootstrapability or tests).
> > >>>>>>
> > >>>>>> 1.  Primarily, we were building value_ranges by modifying them in-flight
> > >>>>>> with no regards to the validity of the resulting range.  By enforcing
> > >>>>>> the API, I noticed we periodically built VR_VARYING / VR_UNDEFINED, but
> > >>>>>> left the equivalence bits uncleared.  This comment in the original
> > >>>>>> header file indicates that this is invalid behavior:
> > >>>>>>
> > >>>>>>       /* Set of SSA names whose value ranges are equivalent to this one.
> > >>>>>>          This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
> > >>>>>>
> > >>>>>> The API now enforces this upon construction.
> > >>>>>>
> > >>>>>> 2. I also saw us setting min/max when VARYING or UNDEFINED was set.
> > >>>>>> This is invalid.  Although these values were being ignored, the API now
> > >>>>>> enforces this.
> > >>>>>>
> > >>>>>> 3. I saw one case in set_value_range_with_overflow() were we were
> > >>>>>> building an invalid range with swapped ranges, where we were silently
> > >>>>>> depending on somebody further up the call chain to swap them for us.
> > >>>>>> I've fixed this at creation.
> > >>>>>>
> > >>>>>> 4. There is one assert in ipcp_vr_lattice which I hope to remove, but
> > >>>>>> left as proof that the original VR_UNDEFINED set was not necessary, as
> > >>>>>> it is now done by default on an empty constructor:
> > >>>>>>
> > >>>>>> -  void init () { m_vr.type = VR_UNDEFINED; }
> > >>>>>> +  void init () { gcc_assert (m_vr.undefined_p ()); }
> > >>>>>>
> > >>>>>> One last note.  The file tree-vrp.c already has a cripple API of sorts
> > >>>>>> in the form of functions (set_value_range_to_varying, etc).  I have
> > >>>>>> tried to keep those functions available, by calling the API under the
> > >>>>>> covers, but would be okay in removing them altogether as a follow-up.
> > >>>>>>
> > >>>>>> Please refer to the RFC wrt the min/max/vrtype accessors, as well as the
> > >>>>>> new tree type field.
> > >>>>>>
> > >>>>>> I am quoting the class declaration below to make it easy to review at a
> > >>>>>> high level.
> > >>>>>>
> > >>>>>> Tested on x86-64 Linux.  All languages, including Ada and Go.
> > >>>>>>
> > >>>>>> OK for trunk?
> > >>>>>
> > >>>>> Reviewing in patch order.
> > >>>>>
> > >>>>>> Aldy
> > >>>>>>
> > >>>>>> class GTY((for_user)) value_range
> > >>>>>> {
> > >>>>>>      public:
> > >>>>>>       value_range ();
> > >>>>>>       value_range (tree type);
> > >>>>>>       value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
> > >>>>>>       bool operator== (const value_range &) const;
> > >>>>>>       bool operator!= (const value_range &) const;
> > >>>>>>       void intersect (const value_range *);
> > >>>>>>       void union_ (const value_range *);
> > >>>>>
> > >>>>> with trailing underscore?  seriously?
> > >>>>
> > >>>> Hey!  You complained about Union() last year, at which point the
> > >>>> consensus was that trailing underscores would be ok for symbol names
> > >>>> that clashed with keywords.
> > >>>
> > >>> ;)
> > >>>
> > >>> I also thought about union_into / union_with.  As opposed to a hypothetical
> > >>>
> > >>>     value_range union (const value_range& a, const value_range& b)
> > >>>
> > >>> function.
> > >>>
> > >>>> And yes, it was also discussed whether we should overload | and ^ for
> > >>>> union and intersection, but was denied for readability and what have yous.
> > >>>>
> > >>>>>
> > >>>>>>       /* Like operator== but ignore equivalence bitmap.  */
> > >>>>>>       bool ignore_equivs_equal_p (const value_range &) const;
> > >>>>>>       /* Like a operator= but update equivalence bitmap efficiently.  */
> > >>>>>>       void copy_with_equiv_update (const value_range *);
> > >>>>>>
> > >>>>>>       /* Types of value ranges.  */
> > >>>>>>       bool undefined_p () const;
> > >>>>>>       bool varying_p () const;
> > >>>>>>       bool symbolic_p () const;
> > >>>>>>       bool numeric_p () const;
> > >>>>>>       void set_undefined (tree = NULL);
> > >>>>>>       void set_varying (tree = NULL);
> > >>>>>
> > >>>>> I'd appreciate comments on those predicates, esp. as you
> > >>>>> replace positive tests by negative ones like in
> > >>>>
> > >>>> Done.
> > >>>>
> > >>>>>
> > >>>>>       /* If we found any usable VR, set the VR to ssa_name and create a
> > >>>>>          PUSH old value in the stack with the old VR.  */
> > >>>>> -  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> > >>>>> +  if (!vr.undefined_p () && !vr.varying_p ())
> > >>>>>         {
> > >>>>>
> > >>>>> I'd also spell numeric_p as constant_p or drop it alltogether
> > >>>>> since !symbolic_p should imply it given varying_p and undefined_p
> > >>>>> are just some special-cases of "numeric_p" (full and empty range).
> > >>>>
> > >>>> Done.
> > >>>>
> > >>>>>
> > >>>>> That said, for the time being I'd use non_symbolic_range_or_anti_range_p
> > >>>>> instead of numeric_p () (seeing that you maybe want to hide the fact
> > >>>>> that we have anti-ranges?)
> > >>>>
> > >>>> Errr... No.
> > >>>>
> > >>>>>
> > >>>>> -  value_range vr = VR_INITIALIZER;
> > >>>>> +  value_range vr (TREE_TYPE (name));
> > >>>>>
> > >>>>> so you basically forgo with the fact that empty ranges are universal?
> > >>>>> I don't like it too much that we have to invent a type here.  Why enforce this
> > >>>>> and not allow/force type == NULL_TREE for empty ranges?
> > >>>>>
> > >>>>> One could argue VARYING is also universal to some extent and useful
> > >>>>> only with context, so similar argument applies to your change forcing
> > >>>>> a type for set_value_range_to_varying.
> > >>>>>
> > >>>>> -      value_range vr = VR_INITIALIZER;
> > >>>>> +      value_range vr;
> > >>>>>
> > >>>>> oh, so you do have a default constructor.
> > >>>>>
> > >>>>>>
> > >>>>>>       /* Equivalence bitmap methods.  */
> > >>>>>>       bitmap equiv () const;
> > >>>>>>       void set_equiv (bitmap);
> > >>>>>
> > >>>>> Err, I think we've settled on _not_ wrapping all member accesses
> > >>>>> with get/set methods, didn't we?  I personally dislike that very much.
> > >>>>>
> > >>>>>>       void equiv_free ();
> > >>>>>>       void equiv_copy (const value_range *);
> > >>>>>>       void equiv_clear ();
> > >>>>>>       void equiv_and (const value_range *);
> > >>>>>>       void equiv_ior (const value_range *);
> > >>>>>
> > >>>>> Likewise I find this useless abstraction.  It's even questionable
> > >>>>> if _free/_clear/_copy are good APIs here.  This should be all
> > >>>>> hidden in intersect/union which I do not find in the API at all...
> > >>>>
> > >>>> I missed that discussion.  We did?  I dislike exposing the internals.
> > >>>> Abstracting things out makes it easier to change things in the future--
> > >>>> or insert instrumenting code, or whatever.
> > >>>
> > >>> OK, I might misremember and it's eventually just my personal taste
> > >>> against slapping a setFoo/getFoo method in a class as the first
> > >>> thing to do after adding a m_Foo member...
> > >>>
> > >>>> That said, I have removed copy/free/and/or.  As you said, it was much
> > >>>> easier to make the details internal to the intersect/union member functions.
> > >>>>
> > >>>> However, I have kept:
> > >>>>
> > >>>>      bitmap equiv () const;
> > >>>>      void set_equiv (bitmap);
> > >>>>      void equiv_clear ();
> > >>>>
> > >>>> I think we can get away with just having a clear, instead of a free, as
> > >>>> it's all in an obstack and there doesn't seem to be any consistent use
> > >>>> of free vs. clear throughout (except one or two, which I've kept).
> > >>>
> > >>> Yeah.
> > >>>
> > >>>> Also, we don't really need to expose set_equiv(), but for its one use in
> > >>>> vr_values::add_equivalence().  One option could be to make vr_values and
> > >>>> value_ranges friends and let add_equivalence touch m_equiv.  But that's
> > >>>> a bit heavy handed.
> > >>>>
> > >>>> Or we could add this to the API instead of set_equiv():
> > >>>>
> > >>>> void
> > >>>> value_range::add_equivalence (bitmap_obstack obstack, tree var)
> > >>>> {
> > >>>> }
> > >>>>
> > >>>> I don't know how I feel about passing the obtack, or including
> > >>>> "bitmap.h" from everywhere tree-vrp.h is used (that is, everywhere).
> > >>>
> > >>> Equivalences are evil ;)  But I guess passing in the obstack works
> > >>> for me.  Maybe as trailing argument, defaulted to NULL in which
> > >>> case we use the default bitmap obstack?
> > >>
> > >> Done.
> > >>
> > >>>
> > >>>> For equiv(), we could remove virtually all of its uses, since 99% of
> > >>>> them are in the form:
> > >>>>
> > >>>>           set_value_range (vr, VR_SOMETHING, min, max, vr->equiv ())
> > >>>>
> > >>>> Instead we could We could provide:
> > >>>>
> > >>>>           vr->update (VR_SOMETHING, min, max);
> > >>>>
> > >>>> ...which is just like set_value_range, but keeping the equivalences intact.
> > >>>
> > >>> Yep, sounds good.
> > >>
> > >> Done.
> > >>
> > >>>
> > >>>>    > hidden in intersect/union which I do not find in the API at all...
> > >>>>
> > >>>> How could you, it was front and center ;-):
> > >>>>
> > >>>>      void intersect (const value_range *);
> > >>>>      void union_ (const value_range *);
> > >>>
> > >>> Missed that in the first review and then failed to delete that comment ;)
> > >>>
> > >>>>>
> > >>>>>>
> > >>>>>>       /* Misc methods.  */
> > >>>>>>       tree type () const;
> > >>>>>
> > >>>>> type() and vrtype() is confusing - value_type() and range_kind() maybe?
> > >>>>
> > >>>> How about we keep type(), since 99% of all uses of "type" in the
> > >>>> compiler are "tree type", so it's easy to figure out.  And instead of
> > >>>> range_kind() we use kind().  It's already obvious it's a range, so
> > >>>> vr->kind() reads fine IMO.
> > >>>
> > >>> Works for me.
> > >>
> > >> Done.
> > >>
> > >>>
> > >>>>>
> > >>>>>>       bool null_p () const;
> > >>>>>>       bool may_contain_p (tree) const;
> > >>>>>>       tree singleton () const;
> > >>>>>
> > >>>>> No documentation? :/   Why null_p but singleton (instead of singleton_p)?
> > >>>>
> > >>>> Documented.
> > >>>>
> > >>>> Singleton returns the singleton if found, otherwise returns NULL.
> > >>>> NULL_P returns true/or false.  I thought the preferred way was for _p to
> > >>>> always return booleans.
> > >>>
> > >>> Ah, missed that "detail"...
> > >>>
> > >>>> I don't feel strongly, so I've renamed it to singleton_p() since a
> > >>>> NULL_TREE is as good as false.  Another option is:
> > >>>>
> > >>>>           bool singleton_p (tree *result = NULL)
> > >>>>
> > >>>> Hmmm...I like this last one.  What do you think?
> > >>>
> > >>> Like it as well.
> > >>
> > >> Done.
> > >>
> > >>>
> > >>>>>
> > >>>>>>       void set_and_canonicalize (enum value_range_type, tree, tree, tree,
> > >>>>>> bitmap);
> > >>>>>
> > >>>>> Why's that necessary if you enforce sanity?
> > >>>>
> > >>>> Canonicalize also does some optimizations like converting anti-ranges
> > >>>> into ranges if possible.  Although I would be OK with putting that
> > >>>> functionality in value_range::set() to be done on creation, I don't know
> > >>>> how I feel about polluting the creation code with fixing swapped min/max:
> > >>>>
> > >>>>      /* Wrong order for min and max, to swap them and the VR type we need
> > >>>>         to adjust them.  */
> > >>>>
> > >>>> It feels wrong to construct a range with swapped end-points, and hope
> > >>>> things turn out ok.  ISTM that canonicalize() clearly specifies intent:
> > >>>> I'm giving you a shitty range, fix it.
> > >>>>
> > >>>> Thoughts?
> > >>>
> > >>> OK, let's keep it the way you had it.  I never liked this part very much
> > >>> (even though I added it!).
> > >>
> > >> Sounds like you need to have a long talk with yourself ;-).
> > >>
> > >>>
> > >>>>>
> > >>>>>>       void dump () const;
> > >>>>>>
> > >>>>>>       /* Temporary accessors that should eventually be removed.  */
> > >>>>>>       enum value_range_type vrtype () const;
> > >>>>>>       tree min () const;
> > >>>>>>       tree max () const;
> > >>>>>>
> > >>>>>>      private:
> > >>>>>>       void set (value_range_type, tree type, tree, tree, bitmap);
> > >>>>>>       void check ();
> > >>>>>>       bool equal_p (const value_range &, bool ignore_equivs) const;
> > >>>>>>
> > >>>>>>       enum value_range_type m_vrtype;
> > >>>>>>      public:
> > >>>>>>       /* These should be private, but GTY is a piece of crap.  */
> > >>>>>>       tree m_min;
> > >>>>>>       tree m_max;
> > >>>>>>       tree m_type;
> > >>>>>
> > >>>>> m_type is redundant (see above).
> > >>>>
> > >>>> Removed.
> > >>>>
> > >>>> Tested on x86-64 Linux.
> > >>>>
> > >>>> Aldy
> > >>>>
> > >>>> p.s. Oh yeah, it wouldn't be an Aldy patch without an irrelevant bit
> > >>>> added for good measure:
> > >>>>
> > >>>> +void
> > >>>> +bitmap_head::dump ()
> > >>>> +{
> > >>>> +  debug (this);
> > >>>> +}
> > >>>>
> > >>>> I find having ->dump() available for each and every structure in GCC
> > >>>> helpful in debugging.  At some point we should standardize on dump(FILE
> > >>>> *) and debug() to dump to stderr.  But alas, there are too many dump()'s
> > >>>> that already dump to stderr :-/.
> > >>>
> > >>> FWIW I like
> > >>>
> > >>> void dump (const bitmap_head&);
> > >>>
> > >>> more since it doesn't clutter the APIs and can theoretically be very
> > >>> easily not built into a release compiler.  And IIRC we already have
> > >>> global overloads of debug () for exactly the reason you cite.  Having
> > >>> both styles is IMHO not good.  (and I've stated my preference - feel
> > >>> free to provide statistics for in-tree uses ;))
> > >>
> > >> Ughh, maybe in the future I'll sit down and convert everything to
> > >> something regular.
> > >>
> > >> Tested with all languages on x86-64 Linux.
> > >>
> > >> OK for trunk?
> > >
> > > You seem to remove vr_values::add_equivalence but then...
> > >
> > > diff --git a/gcc/vr-values.h b/gcc/vr-values.h
> > > index 487a800c1ea..496707856c3 100644
> > > --- a/gcc/vr-values.h
> > > +++ b/gcc/vr-values.h
> > > @@ -72,7 +72,7 @@ class vr_values
> > >     void cleanup_edges_and_switches (void);
> > >
> > >    private:
> > > -  void add_equivalence (bitmap *, const_tree);
> > > +  bitmap add_equivalence (bitmap, const_tree);
> > >     bool vrp_stmt_computes_nonzero (gimple *);
> > >     bool op_with_boolean_value_range_p (tree);
> > >     bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);
> > >
> > > so please remove the method in the class as well.
> > >
> > > OK with that change.
> >
> > I am updating my tree and will commit once a sanity bootstrap succeeds.
> >
> > Thanks so much for your review.
> >
> > Aldy
>
> This caused:
>
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87670
>
> --
> H.J.

Patch

gcc/

	* gimple-ssa-evrp-analyze.c
	(evrp_range_analyzer::try_find_new_range): Adjust for value_range API.
	(evrp_range_analyzer::set_ssa_range_info): Same.
	(evrp_range_analyzer::record_ranges_from_phis): Same.
	(evrp_range_analyzer::record_ranges_from_stmt): Same.
	* gimple-ssa-evrp.c (evrp_dom_walker::before_dom_children): Same.
	* gimple-ssa-sprintf.c (get_int_range): Same.
	(format_integer): Same.
	(sprintf_dom_walker::handle_gimple_call): Same.
	* ipa-cp.c (ipcp_vr_lattice::meet_with_1): Same.
	(ipcp_vr_lattice::top_p): Same.
	(ipcp_vr_lattice::bottom_p): Same.
	(ipcp_vr_lattice::set_to_bottom): Same.
	(ipa_vr_operation_and_type_effects): Same.
	(propagate_vr_across_jump_function): Same.
	(ipcp_store_vr_results): Same.
	* ipa-prop.c (struct ipa_vr_ggc_hash_traits): Same.
	(ipa_print_node_jump_functions_for_edge): Same.
	(ipa_get_value_range): Same.
	(ipa_compute_jump_functions_for_edge): Same.
	(ipa_write_jump_function): Same.
	* tree-ssa-dom.c (simplify_stmt_for_jump_threading): Same.
	* tree-ssa-threadedge.c (record_temporary_equivalences_from_phis):
	Same.
	* vr-values.c (set_value_range_to_nonnegative): Same.
	(set_value_range_to_truthvalue): Same.
	(vr_values::get_value_range): Same.
	(vr_values::set_defs_to_varying): Same.
	(vr_values::update_value_range): Same.
	(symbolic_range_based_on_p): Same.
	(vr_values::op_with_boolean_value_range_p): Same.
	(vr_values::extract_range_for_var_from_comparison_expr): Same.
	(vr_values::extract_range_from_ssa_name): Same.
	(vr_values::extract_range_from_binary_expr): Same.
	(vr_values::extract_range_from_unary_expr): Same.
	(vr_values::extract_range_from_cond_expr): Same.
	(vr_values::extract_range_from_comparison): Same.
	(vr_values::check_for_binary_op_overflow): Same.
	(vr_values::extract_range_basic): Same.
	(vr_values::extract_range_from_assignment): Same.
	(compare_ranges): Same.
	(compare_range_with_value): Same.
	(vr_values::adjust_range_with_scev): Same.
	(vrp_valueize): Same.
	(vrp_valueize_1): Same.
	(vr_values::get_vr_for_comparison): Same.
	(vr_values::compare_name_with_value): Same.
	(vr_values::compare_names): Same.
	(vr_values::vrp_evaluate_conditional): Same.
	(find_case_label_ranges): Same.
	(vr_values::vrp_visit_switch_stmt): Same.
	(vr_values::extract_range_from_phi_node): Same.
	(vr_values::simplify_div_or_mod_using_ranges): Same.
	(vr_values::simplify_bit_ops_using_ranges): Same.
	(test_for_singularity): Same.
	(range_fits_type_p): Same.
	(vr_values::simplify_cond_using_ranges_1): Same.
	(vr_values::simplify_switch_using_ranges): Same.
	(vr_values::simplify_float_conversion_using_ranges): Same.
	(vr_values::two_valued_val_range_p): Same.
	(vr_values::add_equivalence): Rewrite to return adjusted value
	instead of setting a pointer.
	* vr-values.h (vr_values::add_equivalence): Adjust to return
	value.
	(VR_INITIALIZER): Remove.
	* tree-vrp.c (value_range::set): New.
	(value_range::value_range): New.
	(value_range::copy_with_equiv_update): New.
	(value_range::check): New.
	(value_range::equal_p): New.
	(value_range::ignore_equivs_equal_p): New.
	(value_range::operator==): New.
	(value_range::operator!=): New.
	(value_range::symbolic_p): New.
	(value_range::numeric_p): New.
	(value_range::set_undefined): New.
	(value_range::set_varying): New.
	(value_range::may_contain_p): New.
	(value_range::equiv_free): New.
	(value_range::equiv_copy): New.
	(value_range::equiv_clear): New.
	(value_range::equiv_and): New.
	(value_range::equiv_ior): New.
	(value_range::singleton): New.
	(value_range::union_): New.
	(value_range::intersect): New.
	(value_range::dump): New.
	(set_value_range_to_undefined): New.
	(set_value_range_to_varying): New.
	(value_range::set_and_canonicalize): New.
	(set_value_range): Adjust for value_range API.
	(set_and_canonicalize_value_range): Same.
	(copy_value_range): Same.
	(set_value_range_to_nonnull): Same.
	(set_value_range_to_null): Same.
	(range_is_null): Same.
	(range_is_nonnull): Same.
	(range_int_cst_p): Same.
	(range_int_cst_singleton_p): Same.
	(symbolic_range_p): Same.
	(range_includes_zero_p): Same.
	(value_range_constant_singleton): Same.
	(vrp_set_zero_nonzero_bits): Same.
	(ranges_from_anti_range): Same.
	(extract_range_into_wide_ints): Same.
	(extract_range_from_multiplicative_op): Same.
	(set_value_range_with_overflow): Same.
	(extract_range_from_binary_expr_1): Same.
	(extract_range_from_unary_expr): Same.
	(dump_value_range): Same.
	(debug_value_range): Same.
	(vrp_prop::check_array_ref): Same.
	(vrp_prop::check_mem_ref): Same.
	(vrp_prop::vrp_initialize): Same.
	(vrp_prop::visit_stmt): Same.
	(intersect_ranges): Same.
	(vrp_prop::visit_phi): Same.
	(vrp_prop::vrp_finalize): Same.
	(determine_value_range_1): Same.
	(determine_value_range): Same.
	(vrp_intersect_ranges_1): Rename to...
	(vrp_intersect_1): this.
	(vrp_intersect_ranges): Rename to...
	(vrp_intersect): ...this.
	(vrp_meet_1): Rename to...
	(vrp_union_1): ...this.
	(vrp_meet): Rename to...
	(vrp_union): ...this.
	* tree-vrp.h (struct value_range): Rewrite into a proper class.
	(value_range::vrtype): New.
	(value_range::type): New.
	(value_range::equiv): New.
	(value_range::min): New.
	(value_range::max): New.
	(value_range::varying_p): New.
	(value_range::undefined_p): New.
	(value_range::set_equiv): New.
	(value_range::null_p): New.

diff --git a/gcc/gimple-ssa-evrp-analyze.c b/gcc/gimple-ssa-evrp-analyze.c
index e9afa80e191..e3695432c88 100644
--- a/gcc/gimple-ssa-evrp-analyze.c
+++ b/gcc/gimple-ssa-evrp-analyze.c
@@ -82,7 +82,7 @@  value_range *
 evrp_range_analyzer::try_find_new_range (tree name,
 				    tree op, tree_code code, tree limit)
 {
-  value_range vr = VR_INITIALIZER;
+  value_range vr (TREE_TYPE (name));
   value_range *old_vr = get_value_range (name);
 
   /* Discover VR when condition is true.  */
@@ -90,11 +90,11 @@  evrp_range_analyzer::try_find_new_range (tree name,
 							 limit, &vr);
   /* If we found any usable VR, set the VR to ssa_name and create a
      PUSH old value in the stack with the old VR.  */
-  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
+  if (!vr.undefined_p () && !vr.varying_p ())
     {
-      if (old_vr->type == vr.type
-	  && vrp_operand_equal_p (old_vr->min, vr.min)
-	  && vrp_operand_equal_p (old_vr->max, vr.max))
+      if (old_vr->vrtype () == vr.vrtype ()
+	  && vrp_operand_equal_p (old_vr->min (), vr.min ())
+	  && vrp_operand_equal_p (old_vr->max (), vr.max ()))
 	return NULL;
       value_range *new_vr = vr_values->allocate_value_range ();
       *new_vr = vr;
@@ -110,13 +110,10 @@  evrp_range_analyzer::set_ssa_range_info (tree lhs, value_range *vr)
   /* Set the SSA with the value range.  */
   if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
     {
-      if ((vr->type == VR_RANGE
-	   || vr->type == VR_ANTI_RANGE)
-	  && (TREE_CODE (vr->min) == INTEGER_CST)
-	  && (TREE_CODE (vr->max) == INTEGER_CST))
-	set_range_info (lhs, vr->type,
-			wi::to_wide (vr->min),
-			wi::to_wide (vr->max));
+      if (vr->numeric_p ())
+	set_range_info (lhs, vr->vrtype (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
     }
   else if (POINTER_TYPE_P (TREE_TYPE (lhs))
 	   && range_includes_zero_p (vr) == 0)
@@ -241,13 +238,13 @@  evrp_range_analyzer::record_ranges_from_phis (basic_block bb)
       if (virtual_operand_p (lhs))
 	continue;
 
-      value_range vr_result = VR_INITIALIZER;
+      value_range vr_result (TREE_TYPE (lhs));
       bool interesting = stmt_interesting_for_vrp (phi);
       if (!has_unvisited_preds && interesting)
 	vr_values->extract_range_from_phi_node (phi, &vr_result);
       else
 	{
-	  set_value_range_to_varying (&vr_result);
+	  set_value_range_to_varying (&vr_result, TREE_TYPE (lhs));
 	  /* When we have an unvisited executable predecessor we can't
 	     use PHI arg ranges which may be still UNDEFINED but have
 	     to use VARYING for them.  But we can still resort to
@@ -284,7 +281,7 @@  evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
   else if (stmt_interesting_for_vrp (stmt))
     {
       edge taken_edge;
-      value_range vr = VR_INITIALIZER;
+      value_range vr;
       vr_values->extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
       if (output)
 	{
@@ -315,7 +312,7 @@  evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
 		 bitmaps.  Ugh.  */
 	      value_range *new_vr = vr_values->allocate_value_range ();
 	      *new_vr = vr;
-	      new_vr->equiv = NULL;
+	      new_vr->set_equiv (NULL);
 	      push_value_range (output, new_vr);
 	    }
 	}
diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 50e8adc1aad..b075c1051d8 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -161,8 +161,7 @@  evrp_dom_walker::before_dom_children (basic_block bb)
 	      value_range *vr = evrp_range_analyzer.get_value_range (output);
 
 	      /* Mark stmts whose output we fully propagate for removal.  */
-	      if ((vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
-		  && (val = value_range_constant_singleton (vr))
+	      if ((val = value_range_constant_singleton (vr))
 		  && may_propagate_copy (output, val)
 		  && !stmt_could_throw_p (stmt)
 		  && !gimple_has_side_effects (stmt))
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index 471bfc45eb8..5bc5607c92f 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -1052,9 +1052,7 @@  get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 	{
 	  /* Try to determine the range of values of the integer argument.  */
 	  value_range *vr = vr_values->get_value_range (arg);
-	  if (vr->type == VR_RANGE
-	      && TREE_CODE (vr->min) == INTEGER_CST
-	      && TREE_CODE (vr->max) == INTEGER_CST)
+	  if (range_int_cst_p (vr))
 	    {
 	      HOST_WIDE_INT type_min
 		= (TYPE_UNSIGNED (argtype)
@@ -1063,8 +1061,8 @@  get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 
 	      HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype));
 
-	      *pmin = TREE_INT_CST_LOW (vr->min);
-	      *pmax = TREE_INT_CST_LOW (vr->max);
+	      *pmin = TREE_INT_CST_LOW (vr->min ());
+	      *pmax = TREE_INT_CST_LOW (vr->max ());
 
 	      if (*pmin < *pmax)
 		{
@@ -1354,12 +1352,10 @@  format_integer (const directive &dir, tree arg, vr_values *vr_values)
       /* Try to determine the range of values of the integer argument
 	 (range information is not available for pointers).  */
       value_range *vr = vr_values->get_value_range (arg);
-      if (vr->type == VR_RANGE
-	  && TREE_CODE (vr->min) == INTEGER_CST
-	  && TREE_CODE (vr->max) == INTEGER_CST)
+      if (range_int_cst_p (vr))
 	{
-	  argmin = vr->min;
-	  argmax = vr->max;
+	  argmin = vr->min ();
+	  argmax = vr->max ();
 
 	  /* Set KNOWNRANGE if the argument is in a known subrange
 	     of the directive's type and neither width nor precision
@@ -1372,12 +1368,11 @@  format_integer (const directive &dir, tree arg, vr_values *vr_values)
 	  res.argmin = argmin;
 	  res.argmax = argmax;
 	}
-      else if (vr->type == VR_ANTI_RANGE)
+      else if (vr->vrtype () == VR_ANTI_RANGE)
 	{
 	  /* Handle anti-ranges if/when bug 71690 is resolved.  */
 	}
-      else if (vr->type == VR_VARYING
-	       || vr->type == VR_UNDEFINED)
+      else if (vr->varying_p () || vr->undefined_p ())
 	{
 	  /* The argument here may be the result of promoting the actual
 	     argument to int.  Try to determine the type of the actual
@@ -3903,12 +3898,10 @@  sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi)
 	     and use the greater of the two at level 1 and the smaller
 	     of them at level 2.  */
 	  value_range *vr = evrp_range_analyzer.get_value_range (size);
-	  if (vr->type == VR_RANGE
-	      && TREE_CODE (vr->min) == INTEGER_CST
-	      && TREE_CODE (vr->max) == INTEGER_CST)
+	  if (range_int_cst_p (vr))
 	    dstsize = (warn_level < 2
-		       ? TREE_INT_CST_LOW (vr->max)
-		       : TREE_INT_CST_LOW (vr->min));
+		       ? TREE_INT_CST_LOW (vr->max ())
+		       : TREE_INT_CST_LOW (vr->min ()));
 
 	  /* The destination size is not constant.  If the function is
 	     bounded (e.g., snprintf) a lower bound of zero doesn't
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 27ae8e0fe27..3223f32a073 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -314,7 +314,7 @@  public:
   inline bool set_to_bottom ();
   bool meet_with (const value_range *p_vr);
   bool meet_with (const ipcp_vr_lattice &other);
-  void init () { m_vr.type = VR_UNDEFINED; }
+  void init () { gcc_assert (m_vr.undefined_p ()); }
   void print (FILE * f);
 
 private:
@@ -914,28 +914,21 @@  ipcp_vr_lattice::meet_with (const value_range *p_vr)
   return meet_with_1 (p_vr);
 }
 
-/* Meet the current value of the lattice with value ranfge described by
-   OTHER_VR lattice.  */
+/* Meet the current value of the lattice with value range described by
+   OTHER_VR lattice.  Return TRUE if anything changed.  */
 
 bool
 ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
 {
-  tree min = m_vr.min, max = m_vr.max;
-  value_range_type type = m_vr.type;
-
   if (bottom_p ())
     return false;
 
-  if (other_vr->type == VR_VARYING)
+  if (other_vr->varying_p ())
     return set_to_bottom ();
 
-  vrp_meet (&m_vr, other_vr);
-  if (type != m_vr.type
-      || min != m_vr.min
-      || max != m_vr.max)
-    return true;
-  else
-    return false;
+  value_range save (m_vr);
+  m_vr.union_ (other_vr);
+  return !m_vr.ignore_equivs_equal_p (save);
 }
 
 /* Return true if value range information in the lattice is yet unknown.  */
@@ -943,7 +936,7 @@  ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
 bool
 ipcp_vr_lattice::top_p () const
 {
-  return m_vr.type == VR_UNDEFINED;
+  return m_vr.undefined_p ();
 }
 
 /* Return true if value range information in the lattice is known to be
@@ -952,7 +945,7 @@  ipcp_vr_lattice::top_p () const
 bool
 ipcp_vr_lattice::bottom_p () const
 {
-  return m_vr.type == VR_VARYING;
+  return m_vr.varying_p ();
 }
 
 /* Set value range information in the lattice to bottom.  Return true if it
@@ -961,9 +954,10 @@  ipcp_vr_lattice::bottom_p () const
 bool
 ipcp_vr_lattice::set_to_bottom ()
 {
-  if (m_vr.type == VR_VARYING)
+  if (m_vr.varying_p ())
     return false;
-  m_vr.type = VR_VARYING;
+  /* ?? Use any type for VARYING for now.  */
+  m_vr.set_varying (integer_type_node);
   return true;
 }
 
@@ -1882,12 +1876,11 @@  ipa_vr_operation_and_type_effects (value_range *dst_vr, value_range *src_vr,
 				   enum tree_code operation,
 				   tree dst_type, tree src_type)
 {
-  memset (dst_vr, 0, sizeof (*dst_vr));
+  *dst_vr = value_range ();
   extract_range_from_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
-  if (dst_vr->type == VR_RANGE || dst_vr->type == VR_ANTI_RANGE)
-    return true;
-  else
+  if (dst_vr->varying_p () || dst_vr->undefined_p ())
     return false;
+  return true;
 }
 
 /* Propagate value range across jump function JFUNC that is associated with
@@ -1940,11 +1933,7 @@  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;
-	  memset (&tmpvr, 0, sizeof (tmpvr));
-	  tmpvr.type = VR_RANGE;
-	  tmpvr.min = val;
-	  tmpvr.max = val;
+	  value_range tmpvr (VR_RANGE, TREE_TYPE (val), val, val);
 	  return dest_lat->meet_with (&tmpvr);
 	}
     }
@@ -1953,7 +1942,7 @@  propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
   if (jfunc->m_vr
       && ipa_vr_operation_and_type_effects (&vr, jfunc->m_vr, NOP_EXPR,
 					    param_type,
-					    TREE_TYPE (jfunc->m_vr->min)))
+					    jfunc->m_vr->type ()))
     return dest_lat->meet_with (&vr);
   else
     return dest_lat->set_to_bottom ();
@@ -5028,9 +5017,9 @@  ipcp_store_vr_results (void)
 	      && !plats->m_value_range.top_p ())
 	    {
 	      vr.known = true;
-	      vr.type = plats->m_value_range.m_vr.type;
-	      vr.min = wi::to_wide (plats->m_value_range.m_vr.min);
-	      vr.max = wi::to_wide (plats->m_value_range.m_vr.max);
+	      vr.type = plats->m_value_range.m_vr.vrtype ();
+	      vr.min = wi::to_wide (plats->m_value_range.m_vr.min ());
+	      vr.max = wi::to_wide (plats->m_value_range.m_vr.max ());
 	    }
 	  else
 	    {
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 8b19fe3f391..ceecce1241f 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -113,16 +113,16 @@  struct ipa_vr_ggc_hash_traits : public ggc_cache_remove <value_range *>
   static hashval_t
   hash (const value_range *p)
     {
-      gcc_checking_assert (!p->equiv);
-      inchash::hash hstate (p->type);
-      hstate.add_ptr (p->min);
-      hstate.add_ptr (p->max);
+      gcc_checking_assert (!p->equiv ());
+      inchash::hash hstate (p->vrtype ());
+      hstate.add_ptr (p->min ());
+      hstate.add_ptr (p->max ());
       return hstate.end ();
     }
   static bool
   equal (const value_range *a, const value_range *b)
     {
-      return a->type == b->type && a->min == b->min && a->max == b->max;
+      return a->ignore_equivs_equal_p (*b);
     }
   static void
   mark_empty (value_range *&p)
@@ -398,10 +398,10 @@  ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
 	{
 	  fprintf (f, "         VR  ");
 	  fprintf (f, "%s[",
-		   (jump_func->m_vr->type == VR_ANTI_RANGE) ? "~" : "");
-	  print_decs (wi::to_wide (jump_func->m_vr->min), f);
+		   (jump_func->m_vr->vrtype () == VR_ANTI_RANGE) ? "~" : "");
+	  print_decs (wi::to_wide (jump_func->m_vr->min ()), f);
 	  fprintf (f, ", ");
-	  print_decs (wi::to_wide (jump_func->m_vr->max), f);
+	  print_decs (wi::to_wide (jump_func->m_vr->max ()), f);
 	  fprintf (f, "]\n");
 	}
       else
@@ -1791,11 +1791,7 @@  ipa_get_value_range (value_range *tmp)
 static value_range *
 ipa_get_value_range (enum value_range_type type, tree min, tree max)
 {
-  value_range tmp;
-  tmp.type = type;
-  tmp.min = min;
-  tmp.max = max;
-  tmp.equiv = NULL;
+  value_range tmp (type, TREE_TYPE (min), min, max);
   return ipa_get_value_range (&tmp);
 }
 
@@ -1890,16 +1886,13 @@  ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	      && (type = get_range_info (arg, &min, &max))
 	      && (type == VR_RANGE || type == VR_ANTI_RANGE))
 	    {
-	      value_range tmpvr,resvr;
-
-	      tmpvr.type = type;
-	      tmpvr.min = wide_int_to_tree (TREE_TYPE (arg), min);
-	      tmpvr.max = wide_int_to_tree (TREE_TYPE (arg), max);
-	      tmpvr.equiv = NULL;
-	      memset (&resvr, 0, sizeof (resvr));
+	      value_range resvr;
+	      value_range tmpvr (type, TREE_TYPE (arg),
+				 wide_int_to_tree (TREE_TYPE (arg), min),
+				 wide_int_to_tree (TREE_TYPE (arg), max));
 	      extract_range_from_unary_expr (&resvr, NOP_EXPR, param_type,
 					     &tmpvr, TREE_TYPE (arg));
-	      if (resvr.type == VR_RANGE || resvr.type == VR_ANTI_RANGE)
+	      if (!resvr.undefined_p () && !resvr.varying_p ())
 		ipa_set_jfunc_vr (jfunc, &resvr);
 	      else
 		gcc_assert (!jfunc->m_vr);
@@ -4126,9 +4119,9 @@  ipa_write_jump_function (struct output_block *ob,
   if (jump_func->m_vr)
     {
       streamer_write_enum (ob->main_stream, value_rang_type,
-			   VR_LAST, jump_func->m_vr->type);
-      stream_write_tree (ob, jump_func->m_vr->min, true);
-      stream_write_tree (ob, jump_func->m_vr->max, true);
+			   VR_LAST, jump_func->m_vr->vrtype ());
+      stream_write_tree (ob, jump_func->m_vr->min (), true);
+      stream_write_tree (ob, jump_func->m_vr->max (), true);
     }
 }
 
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index f7cc034b26e..cb74ed15d72 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -882,25 +882,27 @@  simplify_stmt_for_jump_threading (gimple *stmt,
 	return NULL_TREE;
 
       value_range *vr = x_vr_values->get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->vrtype () == VR_RANGE)
 	{
 	  size_t i, j;
 
-	  find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+	  find_case_label_range (switch_stmt, vr->min (), vr->max (), &i, &j);
 
 	  if (i == j)
 	    {
 	      tree label = gimple_switch_label (switch_stmt, i);
+	      tree singleton;
 
 	      if (CASE_HIGH (label) != NULL_TREE
-		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
-		     && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
-		  : (tree_int_cst_equal (CASE_LOW (label), vr->min)
-		     && tree_int_cst_equal (vr->min, vr->max)))
+		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min ()) <= 0
+		     && tree_int_cst_compare (CASE_HIGH (label), vr->max ()) >= 0)
+		  : ((singleton = vr->singleton ())
+		     && tree_int_cst_equal (CASE_LOW (label), singleton)))
 		return label;
 
 	      if (i > j)
@@ -908,7 +910,7 @@  simplify_stmt_for_jump_threading (gimple *stmt,
 	    }
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->vrtype () == VR_ANTI_RANGE)
           {
             unsigned n = gimple_switch_num_labels (switch_stmt);
             tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -917,10 +919,10 @@  simplify_stmt_for_jump_threading (gimple *stmt,
             /* The default label will be taken only if the anti-range of the
                operand is entirely outside the bounds of all the (non-default)
                case labels.  */
-            if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+            if (tree_int_cst_compare (vr->min (), CASE_LOW (min_label)) <= 0
                 && (CASE_HIGH (max_label) != NULL_TREE
-                    ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
-                    : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+                    ? tree_int_cst_compare (vr->max (), CASE_HIGH (max_label)) >= 0
+                    : tree_int_cst_compare (vr->max (), CASE_LOW (max_label)) >= 0))
             return gimple_switch_label (switch_stmt, 0);
           }
 	return NULL_TREE;
@@ -936,11 +938,12 @@  simplify_stmt_for_jump_threading (gimple *stmt,
 	{
 	  edge dummy_e;
 	  tree dummy_tree;
-	  value_range new_vr = VR_INITIALIZER;
+	  value_range new_vr;
 	  x_vr_values->extract_range_from_stmt (stmt, &dummy_e,
 					      &dummy_tree, &new_vr);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  tree singleton;
+	  if ((singleton = new_vr.singleton ()))
+	    return singleton;
 	}
     }
   return NULL;
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index a2304493495..9f510730aed 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -166,7 +166,7 @@  record_temporary_equivalences_from_phis (edge e,
 	     away in the VR stack.  */
 	  vr_values *vr_values = evrp_range_analyzer->get_vr_values ();
 	  value_range *new_vr = vr_values->allocate_value_range ();
-	  memset (new_vr, 0, sizeof (value_range));
+	  *new_vr = value_range ();
 
 	  /* There are three cases to consider:
 
@@ -183,7 +183,7 @@  record_temporary_equivalences_from_phis (edge e,
 	  else if (TREE_CODE (src) == INTEGER_CST)
 	    set_value_range_to_value (new_vr, src,  NULL);
 	  else
-	    set_value_range_to_varying (new_vr);
+	    set_value_range_to_varying (new_vr, TREE_TYPE (src));
 
 	  /* This is a temporary range for DST, so push it.  */
 	  evrp_range_analyzer->push_value_range (dst, new_vr);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index cbc2ea2f26b..555f515f609 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -73,6 +73,248 @@  along with GCC; see the file COPYING3.  If not see
    for still active basic-blocks.  */
 static sbitmap *live;
 
+static void vrp_union (value_range *, const value_range *);
+static void vrp_intersect (value_range *, const value_range *);
+
+/* Initialize value_range.  */
+
+void
+value_range::set (enum value_range_type vrtype, tree type,
+		  tree min, tree max, bitmap equiv)
+{
+  m_type = type;
+  m_vrtype = vrtype;
+  m_min = min;
+  m_max = max;
+
+  /* Since updating the equivalence set involves deep copying the
+     bitmaps, only do it if absolutely necessary.
+
+     All equivalence bitmaps are allocated from the same obstack.  So
+     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
+  if (m_equiv == NULL
+      && equiv != NULL)
+    m_equiv = BITMAP_ALLOC (equiv->obstack);
+
+  if (equiv != m_equiv)
+    {
+      if (equiv && !bitmap_empty_p (equiv))
+	bitmap_copy (m_equiv, equiv);
+      else
+	bitmap_clear (m_equiv);
+    }
+  if (flag_checking)
+    check ();
+}
+
+value_range::value_range (value_range_type vrtype, tree type,
+			  tree min, tree max, bitmap equiv)
+{
+  m_equiv = NULL;
+  set (vrtype, type, min, max, equiv);
+}
+
+/* Initialize value_range from FROM and update equivalence table.  */
+
+void
+value_range::copy_with_equiv_update (const value_range *from)
+{
+  set (from->m_vrtype, from->m_type, from->m_min, from->m_max, from->m_equiv);
+}
+
+/* Check the validity of the range.  */
+
+void
+value_range::check ()
+{
+  if (flag_checking
+      && (m_vrtype == VR_RANGE || m_vrtype == VR_ANTI_RANGE))
+    {
+      int cmp;
+
+      gcc_assert (m_min && m_max);
+
+      gcc_assert (!TREE_OVERFLOW_P (m_min) && !TREE_OVERFLOW_P (m_max));
+
+      /* An anti range cannot be [-MIN, +MAX] because that would
+	 be either empty or VR_UNDEFINED.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (m_min)) && m_vrtype == VR_ANTI_RANGE)
+	gcc_assert (!vrp_val_is_min (m_min) || !vrp_val_is_max (m_max));
+
+      cmp = compare_values (m_min, m_max);
+      gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
+    }
+
+  if (flag_checking
+      && (m_vrtype == VR_UNDEFINED || m_vrtype == VR_VARYING))
+    {
+      gcc_assert (m_min == NULL_TREE && m_max == NULL_TREE);
+      gcc_assert (m_equiv == NULL || bitmap_empty_p (m_equiv));
+    }
+}
+
+/* Returns TRUE if THIS == OTHER.  Ignores the equivalence bitmap if
+   IGNORE_EQUIVS is TRUE.  */
+
+bool
+value_range::equal_p (const value_range &other, bool ignore_equivs) const
+{
+ return (m_type == other.m_type
+	 && m_vrtype == other.m_vrtype
+	 && vrp_operand_equal_p (m_min, other.m_min)
+	 && vrp_operand_equal_p (m_max, other.m_max)
+	 && (ignore_equivs
+	     || vrp_bitmap_equal_p (m_equiv, other.m_equiv)));
+}
+
+bool
+value_range::ignore_equivs_equal_p (const value_range &other) const
+{
+  return equal_p (other, /*ignore_equivs=*/true);
+}
+
+bool
+value_range::operator== (const value_range &other) const
+{
+ return equal_p (other, /*ignore_equivs=*/false);
+}
+
+bool
+value_range::operator!= (const value_range &other) const
+{
+ return !(*this == other);
+}
+
+bool
+value_range::symbolic_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && (!is_gimple_min_invariant (m_min)
+	      || !is_gimple_min_invariant (m_max)));
+}
+
+/* NOTE: Numeric is not the inverse of symbolic_p because the range
+   could also be varying or undefined.  Ideally they should be inverse
+   of each other, with varying only applying to symbolics.  Varying of
+   numerics would be represented as [-MIN, +MAX].  */
+
+bool
+value_range::numeric_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && TREE_CODE (m_min) == INTEGER_CST
+	  && TREE_CODE (m_max) == INTEGER_CST);
+}
+
+void
+value_range::set_undefined (tree type)
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+  if (type)
+    m_type = type;
+  else
+    gcc_assert (m_type);
+  *this = value_range (VR_UNDEFINED, m_type, NULL, NULL, m_equiv);
+}
+
+void
+value_range::set_varying (tree type)
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+  if (type)
+    m_type = type;
+  else
+    gcc_assert (m_type);
+  *this = value_range (VR_VARYING, m_type, NULL, NULL, m_equiv);
+}
+
+bool
+value_range::may_contain_p (tree val) const
+{
+  if (varying_p ())
+    return true;
+
+  if (undefined_p ())
+    return true;
+
+  if (m_vrtype == VR_ANTI_RANGE)
+    {
+      int res = value_inside_range (val, m_min, m_max);
+      return res == 0 || res == -2;
+    }
+  return value_inside_range (val, m_min, m_max) != 0;
+}
+
+void
+value_range::equiv_free ()
+{
+  BITMAP_FREE (m_equiv);
+  m_equiv = NULL;
+}
+
+void
+value_range::equiv_copy (const value_range *other)
+{
+  bitmap_copy (m_equiv, other->m_equiv);
+}
+
+void
+value_range::equiv_clear ()
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+}
+
+void
+value_range::equiv_and (const value_range *other)
+{
+  if (m_equiv && other->m_equiv)
+    bitmap_and_into (m_equiv, other->m_equiv);
+}
+
+void
+value_range::equiv_ior (const value_range *other)
+{
+  bitmap_ior_into (m_equiv, other->m_equiv);
+}
+
+/* If value range is a singleton, return the singleton, otherwise
+   return NULL.  Note: A singleton can be any gimple invariant, not
+   just constants.  So, [&x, &x] counts as a singleton.  */
+
+tree
+value_range::singleton () const
+{
+  if (m_vrtype == VR_RANGE
+      && vrp_operand_equal_p (m_min, m_max)
+      && is_gimple_min_invariant (m_min))
+    return m_min;
+  return NULL_TREE;
+}
+
+void
+value_range::union_ (const value_range *other)
+{
+  vrp_union (this, other);
+}
+
+void
+value_range::intersect (const value_range *other)
+{
+  vrp_intersect (this, other);
+}
+
+void
+value_range::dump () const
+{
+  dump_value_range (stderr, this);
+  fprintf (stderr, "\n");
+}
+
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 static bool
@@ -243,80 +485,41 @@  intersect_range_with_nonzero_bits (enum value_range_type vr_type,
 /* Set value range VR to VR_UNDEFINED.  */
 
 static inline void
-set_value_range_to_undefined (value_range *vr)
+set_value_range_to_undefined (value_range *vr, tree type)
 {
-  vr->type = VR_UNDEFINED;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_undefined (type);
 }
 
 /* Set value range VR to VR_VARYING.  */
 
 void
-set_value_range_to_varying (value_range *vr)
+set_value_range_to_varying (value_range *vr, tree type)
 {
-  vr->type = VR_VARYING;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_varying (type);
 }
 
 /* Set value range VR to {T, MIN, MAX, EQUIV}.  */
 
 void
-set_value_range (value_range *vr, enum value_range_type t, tree min,
-		 tree max, bitmap equiv)
+set_value_range (value_range *vr, enum value_range_type vrtype,
+		 tree min, tree max, bitmap equiv)
 {
-  /* Check the validity of the range.  */
-  if (flag_checking
-      && (t == VR_RANGE || t == VR_ANTI_RANGE))
-    {
-      int cmp;
-
-      gcc_assert (min && max);
-
-      gcc_assert (!TREE_OVERFLOW_P (min) && !TREE_OVERFLOW_P (max));
-
-      if (INTEGRAL_TYPE_P (TREE_TYPE (min)) && t == VR_ANTI_RANGE)
-	gcc_assert (!vrp_val_is_min (min) || !vrp_val_is_max (max));
-
-      cmp = compare_values (min, max);
-      gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
-    }
-
-  if (flag_checking
-      && (t == VR_UNDEFINED || t == VR_VARYING))
-    {
-      gcc_assert (min == NULL_TREE && max == NULL_TREE);
-      gcc_assert (equiv == NULL || bitmap_empty_p (equiv));
-    }
-
-  vr->type = t;
-  vr->min = min;
-  vr->max = max;
-
-  /* Since updating the equivalence set involves deep copying the
-     bitmaps, only do it if absolutely necessary.
-
-     All equivalence bitmaps are allocated from the same obstack.  So
-     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
-  if (vr->equiv == NULL
-      && equiv != NULL)
-    vr->equiv = BITMAP_ALLOC (equiv->obstack);
+  gcc_assert (min && max);
+  value_range tmp (vrtype, TREE_TYPE (min), min, max, equiv);
+  vr->copy_with_equiv_update (&tmp);
+}
 
-  if (equiv != vr->equiv)
-    {
-      if (equiv && !bitmap_empty_p (equiv))
-	bitmap_copy (vr->equiv, equiv);
-      else
-	bitmap_clear (vr->equiv);
-    }
+void
+set_value_range (value_range *vr, tree type, enum value_range_type vrtype,
+		 tree min, tree max, bitmap equiv)
+{
+  value_range tmp (vrtype, type, min, max, equiv);
+  vr->copy_with_equiv_update (&tmp);
 }
 
 
-/* Set value range VR to the canonical form of {T, MIN, MAX, EQUIV}.
-   This means adjusting T, MIN and MAX representing the case of a
+/* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
+   This means adjusting VRTYPE, MIN and MAX representing the case of a
    wrapping range with MAX < MIN covering [MIN, type_max] U [type_min, MAX]
    as anti-rage ~[MAX+1, MIN-1].  Likewise for wrapping anti-ranges.
    In corner cases where MAX+1 or MIN-1 wraps this will fall back
@@ -325,18 +528,18 @@  set_value_range (value_range *vr, enum value_range_type t, tree min,
    extract ranges from var + CST op limit.  */
 
 void
-set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
-				  tree min, tree max, bitmap equiv)
+value_range::set_and_canonicalize (enum value_range_type vrtype, tree type,
+				   tree min, tree max, bitmap equiv)
 {
   /* Use the canonical setters for VR_UNDEFINED and VR_VARYING.  */
-  if (t == VR_UNDEFINED)
+  if (vrtype == VR_UNDEFINED)
     {
-      set_value_range_to_undefined (vr);
+      set_undefined (type);
       return;
     }
-  else if (t == VR_VARYING)
+  else if (vrtype == VR_VARYING)
     {
-      set_value_range_to_varying (vr);
+      set_varying (type);
       return;
     }
 
@@ -344,7 +547,7 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
   if (TREE_CODE (min) != INTEGER_CST
       || TREE_CODE (max) != INTEGER_CST)
     {
-      set_value_range (vr, t, min, max, equiv);
+      set_value_range (this, vrtype, min, max, equiv);
       return;
     }
 
@@ -359,7 +562,7 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	 for VR_ANTI_RANGE empty range, so drop to varying as well.  */
       if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
 	{
-	  set_value_range_to_varying (vr);
+	  set_varying (TREE_TYPE (min));
 	  return;
 	}
 
@@ -373,15 +576,15 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	 to varying in this case.  */
       if (tree_int_cst_lt (max, min))
 	{
-	  set_value_range_to_varying (vr);
+	  set_varying (TREE_TYPE (min));
 	  return;
 	}
 
-      t = t == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
+      vrtype = vrtype == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
     }
 
   /* Anti-ranges that can be represented as ranges should be so.  */
-  if (t == VR_ANTI_RANGE)
+  if (vrtype == VR_ANTI_RANGE)
     {
       /* For -fstrict-enums we may receive out-of-range ranges so consider
          values < -INF and values > INF as -INF/INF as well.  */
@@ -395,7 +598,7 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	{
 	  /* We cannot deal with empty ranges, drop to varying.
 	     ???  This could be VR_UNDEFINED instead.  */
-	  set_value_range_to_varying (vr);
+	  set_varying (type);
 	  return;
 	}
       else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
@@ -407,7 +610,7 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	    min = max = vrp_val_max (TREE_TYPE (min));
 	  else
 	    min = max = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
+	  vrtype = VR_RANGE;
 	}
       else if (is_min
 	       /* As a special exception preserve non-null ranges.  */
@@ -417,14 +620,14 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 	  tree one = build_int_cst (TREE_TYPE (max), 1);
 	  min = int_const_binop (PLUS_EXPR, max, one);
 	  max = vrp_val_max (TREE_TYPE (max));
-	  t = VR_RANGE;
+	  vrtype = VR_RANGE;
         }
       else if (is_max)
         {
 	  tree one = build_int_cst (TREE_TYPE (min), 1);
 	  max = int_const_binop (MINUS_EXPR, min, one);
 	  min = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
+	  vrtype = VR_RANGE;
         }
     }
 
@@ -432,7 +635,7 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
      to make sure VRP iteration terminates, otherwise we can get into
      oscillations.  */
 
-  set_value_range (vr, t, min, max, equiv);
+  set_value_range (this, type, vrtype, min, max, equiv);
 }
 
 /* Copy value range FROM into value range TO.  */
@@ -440,7 +643,7 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 void
 copy_value_range (value_range *to, const value_range *from)
 {
-  set_value_range (to, from->type, from->min, from->max, from->equiv);
+  to->copy_with_equiv_update (from);
 }
 
 /* Set value range VR to a single value.  This function is only called
@@ -462,7 +665,7 @@  void
 set_value_range_to_nonnull (value_range *vr, tree type)
 {
   tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv);
+  set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv ());
 }
 
 
@@ -471,7 +674,7 @@  set_value_range_to_nonnull (value_range *vr, tree type)
 void
 set_value_range_to_null (value_range *vr, tree type)
 {
-  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv);
+  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv ());
 }
 
 /* Return true, if VAL1 and VAL2 are equal values for VRP purposes.  */
@@ -503,9 +706,15 @@  vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
 static inline bool
 range_is_null (const value_range *vr)
 {
-  return vr->type == VR_RANGE
-	 && integer_zerop (vr->min)
-	 && integer_zerop (vr->max);
+  return vr->null_p ();
+}
+
+static inline bool
+range_is_nonnull (const value_range *vr)
+{
+  return (vr->vrtype () == VR_ANTI_RANGE
+	  && vr->min () == vr->max ()
+	  && integer_zerop (vr->min ()));
 }
 
 /* Return true if max and min of VR are INTEGER_CST.  It's not necessary
@@ -514,9 +723,9 @@  range_is_null (const value_range *vr)
 bool
 range_int_cst_p (const value_range *vr)
 {
-  return (vr->type == VR_RANGE
-	  && TREE_CODE (vr->max) == INTEGER_CST
-	  && TREE_CODE (vr->min) == INTEGER_CST);
+  return (vr->vrtype () == VR_RANGE
+	  && TREE_CODE (vr->min ()) == INTEGER_CST
+	  && TREE_CODE (vr->max ()) == INTEGER_CST);
 }
 
 /* Return true if VR is a INTEGER_CST singleton.  */
@@ -525,16 +734,7 @@  bool
 range_int_cst_singleton_p (const value_range *vr)
 {
   return (range_int_cst_p (vr)
-	  && tree_int_cst_equal (vr->min, vr->max));
-}
-
-/* Return true if value range VR involves at least one symbol.  */
-
-bool
-symbolic_range_p (const value_range *vr)
-{
-  return (!is_gimple_min_invariant (vr->min)
-          || !is_gimple_min_invariant (vr->max));
+	  && tree_int_cst_equal (vr->min (), vr->max ()));
 }
 
 /* Return the single symbol (an SSA_NAME) contained in T if any, or NULL_TREE
@@ -849,34 +1049,20 @@  value_inside_range (tree val, tree min, tree max)
 bool
 range_includes_zero_p (const value_range *vr)
 {
-  if (vr->type == VR_VARYING)
-    return true;
-
-  /* Ughh, we don't know.  We choose not to optimize.  */
-  if (vr->type == VR_UNDEFINED)
-    return true;
-
-  tree zero = build_int_cst (TREE_TYPE (vr->min), 0);
-  if (vr->type == VR_ANTI_RANGE)
-    {
-      int res = value_inside_range (zero, vr->min, vr->max);
-      return res == 0 || res == -2;
-    }
-  return value_inside_range (zero, vr->min, vr->max) != 0;
+  tree zero = build_int_cst (vr->type (), 0);
+  return vr->may_contain_p (zero);
 }
 
-/* If *VR has a value rante that is a single constant value return that,
-   otherwise return NULL_TREE.  */
+/* If *VR has a value range that is a single constant value return that,
+   otherwise return NULL_TREE.
+
+   ?? This actually returns TRUE for [&x, &x], so perhaps "constant"
+   is not the best name.  */
 
 tree
 value_range_constant_singleton (const value_range *vr)
 {
-  if (vr->type == VR_RANGE
-      && vrp_operand_equal_p (vr->min, vr->max)
-      && is_gimple_min_invariant (vr->min))
-    return vr->min;
-
-  return NULL_TREE;
+  return vr->singleton ();
 }
 
 /* Value range wrapper for wide_int_range_set_zero_nonzero_bits.
@@ -899,8 +1085,8 @@  vrp_set_zero_nonzero_bits (const tree expr_type,
       return false;
     }
   wide_int_range_set_zero_nonzero_bits (TYPE_SIGN (expr_type),
-					wi::to_wide (vr->min),
-					wi::to_wide (vr->max),
+					wi::to_wide (vr->min ()),
+					wi::to_wide (vr->max ()),
 					*may_be_nonzero, *must_be_nonzero);
   return true;
 }
@@ -914,40 +1100,36 @@  static bool
 ranges_from_anti_range (const value_range *ar,
 			value_range *vr0, value_range *vr1)
 {
-  tree type = TREE_TYPE (ar->min);
+  tree type = ar->type ();
 
-  vr0->type = VR_UNDEFINED;
-  vr1->type = VR_UNDEFINED;
+  vr0->set_undefined (type);
+  vr1->set_undefined (type);
 
   /* As a future improvement, we could handle ~[0, A] as: [-INF, -1] U
      [A+1, +INF].  Not sure if this helps in practice, though.  */
 
-  if (ar->type != VR_ANTI_RANGE
-      || TREE_CODE (ar->min) != INTEGER_CST
-      || TREE_CODE (ar->max) != INTEGER_CST
+  if (ar->vrtype () != VR_ANTI_RANGE
+      || TREE_CODE (ar->min ()) != INTEGER_CST
+      || TREE_CODE (ar->max ()) != INTEGER_CST
       || !vrp_val_min (type)
       || !vrp_val_max (type))
     return false;
 
-  if (!vrp_val_is_min (ar->min))
-    {
-      vr0->type = VR_RANGE;
-      vr0->min = vrp_val_min (type);
-      vr0->max = wide_int_to_tree (type, wi::to_wide (ar->min) - 1);
-    }
-  if (!vrp_val_is_max (ar->max))
-    {
-      vr1->type = VR_RANGE;
-      vr1->min = wide_int_to_tree (type, wi::to_wide (ar->max) + 1);
-      vr1->max = vrp_val_max (type);
-    }
-  if (vr0->type == VR_UNDEFINED)
+  if (!vrp_val_is_min (ar->min ()))
+    *vr0 = value_range (VR_RANGE, type,
+			vrp_val_min (type),
+			wide_int_to_tree (type, wi::to_wide (ar->min ()) - 1));
+  if (!vrp_val_is_max (ar->max ()))
+    *vr1 = value_range (VR_RANGE, type,
+			wide_int_to_tree (type, wi::to_wide (ar->max ()) + 1),
+			vrp_val_max (type));
+  if (vr0->undefined_p ())
     {
       *vr0 = *vr1;
-      vr1->type = VR_UNDEFINED;
+      vr1->set_undefined (type);
     }
 
-  return vr0->type != VR_UNDEFINED;
+  return !vr0->undefined_p ();
 }
 
 /* Extract the components of a value range into a pair of wide ints in
@@ -961,13 +1143,11 @@  extract_range_into_wide_ints (const value_range *vr,
 			      signop sign, unsigned prec,
 			      wide_int &wmin, wide_int &wmax)
 {
-  if ((vr->type == VR_RANGE
-       || vr->type == VR_ANTI_RANGE)
-      && TREE_CODE (vr->min) == INTEGER_CST
-      && TREE_CODE (vr->max) == INTEGER_CST)
+  gcc_assert (vr->vrtype () != VR_ANTI_RANGE || vr->symbolic_p ());
+  if (range_int_cst_p (vr))
     {
-      wmin = wi::to_wide (vr->min);
-      wmax = wi::to_wide (vr->max);
+      wmin = wi::to_wide (vr->min ());
+      wmax = wi::to_wide (vr->max ());
     }
   else
     {
@@ -994,14 +1174,15 @@  extract_range_from_multiplicative_op (value_range *vr,
 	      || code == ROUND_DIV_EXPR
 	      || code == RSHIFT_EXPR
 	      || code == LSHIFT_EXPR);
-  gcc_assert (vr0->type == VR_RANGE && vr0->type == vr1->type);
+  gcc_assert (vr0->vrtype () == VR_RANGE
+	      && vr0->vrtype () == vr1->vrtype ());
 
-  tree type = TREE_TYPE (vr0->min);
+  tree type = vr0->type ();
   wide_int res_lb, res_ub;
-  wide_int vr0_lb = wi::to_wide (vr0->min);
-  wide_int vr0_ub = wi::to_wide (vr0->max);
-  wide_int vr1_lb = wi::to_wide (vr1->min);
-  wide_int vr1_ub = wi::to_wide (vr1->max);
+  wide_int vr0_lb = wi::to_wide (vr0->min ());
+  wide_int vr0_ub = wi::to_wide (vr0->max ());
+  wide_int vr1_lb = wi::to_wide (vr1->min ());
+  wide_int vr1_ub = wi::to_wide (vr1->max ());
   bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
   bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
   unsigned prec = TYPE_PRECISION (type);
@@ -1010,11 +1191,11 @@  extract_range_from_multiplicative_op (value_range *vr,
 					 code, TYPE_SIGN (type), prec,
 					 vr0_lb, vr0_ub, vr1_lb, vr1_ub,
 					 overflow_undefined, overflow_wraps))
-    set_and_canonicalize_value_range (vr, VR_RANGE,
-				      wide_int_to_tree (type, res_lb),
-				      wide_int_to_tree (type, res_ub), NULL);
+    vr->set_and_canonicalize (VR_RANGE, type,
+			      wide_int_to_tree (type, res_lb),
+			      wide_int_to_tree (type, res_ub), NULL);
   else
-    set_value_range_to_varying (vr);
+    set_value_range_to_varying (vr, type);
 }
 
 /* If BOUND will include a symbolic bound, adjust it accordingly,
@@ -1114,14 +1295,12 @@  set_value_range_with_overflow (value_range &vr,
 {
   const signop sgn = TYPE_SIGN (type);
   const unsigned int prec = TYPE_PRECISION (type);
-  vr.type = VR_RANGE;
-  vr.equiv = NULL;
 
   /* For one bit precision if max < min, then the swapped
      range covers all values.  */
   if (prec == 1 && wi::lt_p (wmax, wmin, sgn))
     {
-      set_value_range_to_varying (&vr);
+      set_value_range_to_varying (&vr, type);
       return;
     }
 
@@ -1133,10 +1312,18 @@  set_value_range_with_overflow (value_range &vr,
       wide_int tmax = wide_int::from (wmax, prec, sgn);
       if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE))
 	{
-	  /* No overflow or both overflow or underflow.  The
-	     range kind stays VR_RANGE.  */
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  /* If the limits are swapped, we wrapped around and cover
+	     the entire range.  We have a similar check at the end of
+	     extract_range_from_binary_expr_1.  */
+	  if (wi::gt_p (tmin, tmax, sgn))
+	    vr.set_varying (type);
+	  else
+	    /* No overflow or both overflow or underflow.  The
+	       range kind stays VR_RANGE.  */
+	    vr = value_range (VR_RANGE, type,
+			      wide_int_to_tree (type, tmin),
+			      wide_int_to_tree (type, tmax));
+	  return;
 	}
       else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
 	       || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
@@ -1145,7 +1332,6 @@  set_value_range_with_overflow (value_range &vr,
 	     changes to VR_ANTI_RANGE.  */
 	  bool covers = false;
 	  wide_int tem = tmin;
-	  vr.type = VR_ANTI_RANGE;
 	  tmin = tmax + 1;
 	  if (wi::cmp (tmin, tmax, sgn) < 0)
 	    covers = true;
@@ -1157,16 +1343,18 @@  set_value_range_with_overflow (value_range &vr,
 	     types values.  */
 	  if (covers || wi::cmp (tmin, tmax, sgn) > 0)
 	    {
-	      set_value_range_to_varying (&vr);
+	      set_value_range_to_varying (&vr, type);
 	      return;
 	    }
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  vr = value_range (VR_ANTI_RANGE, type,
+			    wide_int_to_tree (type, tmin),
+			    wide_int_to_tree (type, tmax));
+	  return;
 	}
       else
 	{
 	  /* Other underflow and/or overflow, drop to VR_VARYING.  */
-	  set_value_range_to_varying (&vr);
+	  set_value_range_to_varying (&vr, type);
 	  return;
 	}
     }
@@ -1176,19 +1364,21 @@  set_value_range_with_overflow (value_range &vr,
 	 value.  */
       wide_int type_min = wi::min_value (prec, sgn);
       wide_int type_max = wi::max_value (prec, sgn);
+      tree min, max;
       if (min_ovf == wi::OVF_UNDERFLOW)
-	vr.min = wide_int_to_tree (type, type_min);
+	min = wide_int_to_tree (type, type_min);
       else if (min_ovf == wi::OVF_OVERFLOW)
-	vr.min = wide_int_to_tree (type, type_max);
+	min = wide_int_to_tree (type, type_max);
       else
-	vr.min = wide_int_to_tree (type, wmin);
+	min = wide_int_to_tree (type, wmin);
 
       if (max_ovf == wi::OVF_UNDERFLOW)
-	vr.max = wide_int_to_tree (type, type_min);
+	max = wide_int_to_tree (type, type_min);
       else if (max_ovf == wi::OVF_OVERFLOW)
-	vr.max = wide_int_to_tree (type, type_max);
+	max = wide_int_to_tree (type, type_max);
       else
-	vr.max = wide_int_to_tree (type, wmax);
+	max = wide_int_to_tree (type, wmax);
+      vr = value_range (VR_RANGE, type, min, max);
     }
 }
 
@@ -1205,7 +1395,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
   signop sign = TYPE_SIGN (expr_type);
   unsigned int prec = TYPE_PRECISION (expr_type);
   value_range vr0 = *vr0_, vr1 = *vr1_;
-  value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+  value_range vrtem0 (expr_type), vrtem1 (expr_type);
   enum value_range_type type;
   tree min = NULL_TREE, max = NULL_TREE;
   int cmp;
@@ -1213,7 +1403,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
   if (!INTEGRAL_TYPE_P (expr_type)
       && !POINTER_TYPE_P (expr_type))
     {
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, expr_type);
       return;
     }
 
@@ -1237,33 +1427,30 @@  extract_range_from_binary_expr_1 (value_range *vr,
       && code != BIT_IOR_EXPR
       && code != BIT_XOR_EXPR)
     {
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, expr_type);
       return;
     }
 
   /* If both ranges are UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED && vr1.type == VR_UNDEFINED)
+  if (vr0.undefined_p () && vr1.undefined_p ())
     {
-      set_value_range_to_undefined (vr);
+      set_value_range_to_undefined (vr, expr_type);
       return;
     }
   /* If one of the ranges is UNDEFINED drop it to VARYING for the following
      code.  At some point we may want to special-case operations that
      have UNDEFINED result for all or some value-ranges of the not UNDEFINED
      operand.  */
-  else if (vr0.type == VR_UNDEFINED)
-    set_value_range_to_varying (&vr0);
-  else if (vr1.type == VR_UNDEFINED)
-    set_value_range_to_varying (&vr1);
+  else if (vr0.undefined_p ())
+    set_value_range_to_varying (&vr0, vr0.type ());
+  else if (vr1.undefined_p ())
+    set_value_range_to_varying (&vr1, vr1.type ());
 
   /* We get imprecise results from ranges_from_anti_range when
      code is EXACT_DIV_EXPR.  We could mask out bits in the resulting
-     range, but then we also need to hack up vrp_meet.  It's just
+     range, but then we also need to hack up vrp_union.  It's just
      easier to special case when vr0 is ~[0,0] for EXACT_DIV_EXPR.  */
-  if (code == EXACT_DIV_EXPR
-      && vr0.type == VR_ANTI_RANGE
-      && vr0.min == vr0.max
-      && integer_zerop (vr0.min))
+  if (code == EXACT_DIV_EXPR && range_is_nonnull (&vr0))
     {
       set_value_range_to_nonnull (vr, expr_type);
       return;
@@ -1271,36 +1458,35 @@  extract_range_from_binary_expr_1 (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express ~[] op X as ([]' op X) U ([]'' op X).  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.vrtype () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
-	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
-					    &vrtem1, vr1_);
-	  vrp_meet (vr, &vrres);
+	  value_range vrres (expr_type);
+	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,					    &vrtem1, vr1_);
+	  vr->union_ (&vrres);
 	}
       return;
     }
   /* Likewise for X op ~[].  */
-  if (vr1.type == VR_ANTI_RANGE
+  if (vr1.vrtype () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr1, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres (expr_type);
 	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
 					    vr0_, &vrtem1);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
 
   /* The type of the resulting value range defaults to VR0.TYPE.  */
-  type = vr0.type;
+  type = vr0.vrtype ();
 
   /* Refuse to operate on VARYING ranges, ranges of different kinds
      and symbolic ranges.  As an exception, we allow BIT_{AND,IOR}
@@ -1323,13 +1509,13 @@  extract_range_from_binary_expr_1 (value_range *vr,
       && code != MINUS_EXPR
       && code != RSHIFT_EXPR
       && code != POINTER_PLUS_EXPR
-      && (vr0.type == VR_VARYING
-	  || vr1.type == VR_VARYING
-	  || vr0.type != vr1.type
-	  || symbolic_range_p (&vr0)
-	  || symbolic_range_p (&vr1)))
+      && (vr0.varying_p ()
+	  || vr1.varying_p ()
+	  || vr0.vrtype () != vr1.vrtype ()
+	  || vr0.symbolic_p ()
+	  || vr1.symbolic_p ()))
     {
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, expr_type);
       return;
     }
 
@@ -1347,7 +1533,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	  else if (range_is_null (&vr0) && range_is_null (&vr1))
 	    set_value_range_to_null (vr, expr_type);
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, expr_type);
 	}
       else if (code == POINTER_PLUS_EXPR)
 	{
@@ -1359,7 +1545,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	  else if (range_is_null (&vr0) && range_is_null (&vr1))
 	    set_value_range_to_null (vr, expr_type);
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, expr_type);
 	}
       else if (code == BIT_AND_EXPR)
 	{
@@ -1370,10 +1556,10 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	  else if (range_is_null (&vr0) || range_is_null (&vr1))
 	    set_value_range_to_null (vr, expr_type);
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, expr_type);
 	}
       else
-	set_value_range_to_varying (vr);
+	set_value_range_to_varying (vr, expr_type);
 
       return;
     }
@@ -1385,24 +1571,20 @@  extract_range_from_binary_expr_1 (value_range *vr,
       /* This will normalize things such that calculating
 	 [0,0] - VR_VARYING is not dropped to varying, but is
 	 calculated as [MIN+1, MAX].  */
-      if (vr0.type == VR_VARYING)
-	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = vrp_val_min (expr_type);
-	  vr0.max = vrp_val_max (expr_type);
-	}
-      if (vr1.type == VR_VARYING)
-	{
-	  vr1.type = VR_RANGE;
-	  vr1.min = vrp_val_min (expr_type);
-	  vr1.max = vrp_val_max (expr_type);
-	}
+      if (vr0.varying_p ())
+	vr0 = value_range (VR_RANGE, vr0.type (),
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type), vr0.equiv ());
+      if (vr1.varying_p ())
+	vr1 = value_range (VR_RANGE, vr1.type (),
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type), vr0.equiv ());
 
       const bool minus_p = (code == MINUS_EXPR);
-      tree min_op0 = vr0.min;
-      tree min_op1 = minus_p ? vr1.max : vr1.min;
-      tree max_op0 = vr0.max;
-      tree max_op1 = minus_p ? vr1.min : vr1.max;
+      tree min_op0 = vr0.min ();
+      tree min_op1 = minus_p ? vr1.max () : vr1.min ();
+      tree max_op0 = vr0.max ();
+      tree max_op1 = minus_p ? vr1.min () : vr1.max ();
       tree sym_min_op0 = NULL_TREE;
       tree sym_min_op1 = NULL_TREE;
       tree sym_max_op0 = NULL_TREE;
@@ -1415,7 +1597,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	 single-symbolic ranges, try to compute the precise resulting range,
 	 but only if we know that this resulting range will also be constant
 	 or single-symbolic.  */
-      if (vr0.type == VR_RANGE && vr1.type == VR_RANGE
+      if (vr0.vrtype () == VR_RANGE && vr1.vrtype () == VR_RANGE
 	  && (TREE_CODE (min_op0) == INTEGER_CST
 	      || (sym_min_op0
 		  = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
@@ -1448,28 +1630,26 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	  if (((bool)min_ovf && sym_min_op0 != sym_min_op1)
 	      || ((bool)max_ovf && sym_max_op0 != sym_max_op1))
 	    {
-	      set_value_range_to_varying (vr);
+	      set_value_range_to_varying (vr, expr_type);
 	      return;
 	    }
 
 	  /* Adjust the range for possible overflow.  */
 	  set_value_range_with_overflow (*vr, expr_type,
 					 wmin, wmax, min_ovf, max_ovf);
-	  if (vr->type == VR_VARYING)
+	  if (vr->varying_p ())
 	    return;
 
 	  /* Build the symbolic bounds if needed.  */
-	  adjust_symbolic_bound (vr->min, code, expr_type,
+	  min = vr->min ();
+	  max = vr->max ();
+	  adjust_symbolic_bound (min, code, expr_type,
 				 sym_min_op0, sym_min_op1,
 				 neg_min_op0, neg_min_op1);
-	  adjust_symbolic_bound (vr->max, code, expr_type,
+	  adjust_symbolic_bound (max, code, expr_type,
 				 sym_max_op0, sym_max_op1,
 				 neg_max_op0, neg_max_op1);
-	  /* ?? It would probably be cleaner to eliminate min/max/type
-	     entirely and hold these values in VR directly.  */
-	  min = vr->min;
-	  max = vr->max;
-	  type = vr->type;
+	  type = vr->vrtype ();
 	}
       else
 	{
@@ -1485,7 +1665,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	     a single range or anti-range as the above is
 		 [-INF+1, +INF(OVF)] intersected with ~[5, 5]
 	     but one could use a scheme similar to equivalences for this. */
-	  set_value_range_to_varying (vr);
+	  set_value_range_to_varying (vr, expr_type);
 	  return;
 	}
     }
@@ -1503,7 +1683,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 			 wide_int_to_tree (expr_type, wmin),
 			 wide_int_to_tree (expr_type, wmax), NULL);
       else
-	set_value_range_to_varying (vr);
+	set_value_range_to_varying (vr, expr_type);
       return;
     }
   else if (code == MULT_EXPR)
@@ -1511,7 +1691,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
       if (!range_int_cst_p (&vr0)
 	  || !range_int_cst_p (&vr1))
 	{
-	  set_value_range_to_varying (vr);
+	  set_value_range_to_varying (vr, expr_type);
 	  return;
 	}
       extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
@@ -1522,19 +1702,21 @@  extract_range_from_binary_expr_1 (value_range *vr,
     {
       if (range_int_cst_p (&vr1)
 	  && !wide_int_range_shift_undefined_p (prec,
-						wi::to_wide (vr1.min),
-						wi::to_wide (vr1.max)))
+						wi::to_wide (vr1.min ()),
+						wi::to_wide (vr1.max ())))
 	{
 	  if (code == RSHIFT_EXPR)
 	    {
 	      /* Even if vr0 is VARYING or otherwise not usable, we can derive
 		 useful ranges just from the shift count.  E.g.
 		 x >> 63 for signed 64-bit x is always [-1, 0].  */
-	      if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
+	      if (vr0.vrtype () != VR_RANGE || vr0.symbolic_p ())
 		{
-		  vr0.type = type = VR_RANGE;
-		  vr0.min = vrp_val_min (expr_type);
-		  vr0.max = vrp_val_max (expr_type);
+		  type = VR_RANGE;
+		  vr0 = value_range (type, vr0.type (),
+				     vrp_val_min (expr_type),
+				     vrp_val_max (expr_type),
+				     vr0.equiv ());
 		}
 	      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
 	      return;
@@ -1544,22 +1726,22 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	    {
 	      wide_int res_lb, res_ub;
 	      if (wide_int_range_lshift (res_lb, res_ub, sign, prec,
-					 wi::to_wide (vr0.min),
-					 wi::to_wide (vr0.max),
-					 wi::to_wide (vr1.min),
-					 wi::to_wide (vr1.max),
+					 wi::to_wide (vr0.min ()),
+					 wi::to_wide (vr0.max ()),
+					 wi::to_wide (vr1.min ()),
+					 wi::to_wide (vr1.max ()),
 					 TYPE_OVERFLOW_UNDEFINED (expr_type),
 					 TYPE_OVERFLOW_WRAPS (expr_type)))
 		{
 		  min = wide_int_to_tree (expr_type, res_lb);
 		  max = wide_int_to_tree (expr_type, res_ub);
-		  set_and_canonicalize_value_range (vr, VR_RANGE,
-						    min, max, NULL);
+		  vr->set_and_canonicalize (VR_RANGE, expr_type, min, max,
+					    NULL);
 		  return;
 		}
 	    }
 	}
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, expr_type);
       return;
     }
   else if (code == TRUNC_DIV_EXPR
@@ -1575,7 +1757,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
       /* Special case explicit division by zero as undefined.  */
       if (range_is_null (&vr1))
 	{
-	  set_value_range_to_undefined (vr);
+	  set_value_range_to_undefined (vr, expr_type);
 	  return;
 	}
 
@@ -1597,7 +1779,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 			       TYPE_OVERFLOW_WRAPS (expr_type),
 			       extra_range_p, extra_min, extra_max))
 	{
-	  set_value_range_to_varying (vr);
+	  set_value_range_to_varying (vr, expr_type);
 	  return;
 	}
       set_value_range (vr, VR_RANGE,
@@ -1605,11 +1787,11 @@  extract_range_from_binary_expr_1 (value_range *vr,
 		       wide_int_to_tree (expr_type, wmax), NULL);
       if (extra_range_p)
 	{
-	  value_range extra_range = VR_INITIALIZER;
+	  value_range extra_range (expr_type);
 	  set_value_range (&extra_range, VR_RANGE,
 			   wide_int_to_tree (expr_type, extra_min),
 			   wide_int_to_tree (expr_type, extra_max), NULL);
-	  vrp_meet (vr, &extra_range);
+	  vr->union_ (&extra_range);
 	}
       return;
     }
@@ -1617,7 +1799,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
     {
       if (range_is_null (&vr1))
 	{
-	  set_value_range_to_undefined (vr);
+	  set_value_range_to_undefined (vr, expr_type);
 	  return;
 	}
       wide_int wmin, wmax, tmp;
@@ -1658,7 +1840,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	      set_value_range (vr, VR_RANGE, min, max, NULL);
 	    }
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, expr_type);
 	  return;
 	}
       else if (code == BIT_IOR_EXPR)
@@ -1676,7 +1858,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	      set_value_range (vr, VR_RANGE, min, max, NULL);
 	    }
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, expr_type);
 	  return;
 	}
       else if (code == BIT_XOR_EXPR)
@@ -1692,7 +1874,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	      set_value_range (vr, VR_RANGE, min, max, NULL);
 	    }
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, expr_type);
 	  return;
 	}
     }
@@ -1706,7 +1888,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
       || max == NULL_TREE
       || TREE_OVERFLOW_P (max))
     {
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, expr_type);
       return;
     }
 
@@ -1715,7 +1897,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
      Note that we do accept [-INF, -INF] and [+INF, +INF].  */
   if (vrp_val_is_min (min) && vrp_val_is_max (max))
     {
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, expr_type);
       return;
     }
 
@@ -1725,7 +1907,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
       /* If the new range has its limits swapped around (MIN > MAX),
 	 then the operation caused one of them to wrap around, mark
 	 the new range VARYING.  */
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, expr_type);
     }
   else
     set_value_range (vr, type, min, max, NULL);
@@ -1742,7 +1924,9 @@  extract_range_from_unary_expr (value_range *vr,
 {
   signop sign = TYPE_SIGN (type);
   unsigned int prec = TYPE_PRECISION (type);
-  value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+  value_range vr0 = *vr0_;
+  value_range vrtem0 (vr0.type ());
+  value_range vrtem1 (vr0.type ());
 
   /* VRP only operates on integral and pointer types.  */
   if (!(INTEGRAL_TYPE_P (op0_type)
@@ -1750,14 +1934,14 @@  extract_range_from_unary_expr (value_range *vr,
       || !(INTEGRAL_TYPE_P (type)
 	   || POINTER_TYPE_P (type)))
     {
-      set_value_range_to_varying (vr);
+      set_value_range_to_varying (vr, type);
       return;
     }
 
   /* If VR0 is UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED)
+  if (vr0.undefined_p ())
     {
-      set_value_range_to_undefined (vr);
+      set_value_range_to_undefined (vr, type);
       return;
     }
 
@@ -1772,7 +1956,7 @@  extract_range_from_unary_expr (value_range *vr,
     {
       /* -X is simply 0 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range zero = VR_INITIALIZER;
+      value_range zero (type);
       set_value_range_to_value (&zero, build_int_cst (type, 0), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR, type, &zero, &vr0);
       return;
@@ -1781,7 +1965,7 @@  extract_range_from_unary_expr (value_range *vr,
     {
       /* ~X is simply -1 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range minusone = VR_INITIALIZER;
+      value_range minusone (type);
       set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
 					type, &minusone, &vr0);
@@ -1790,16 +1974,16 @@  extract_range_from_unary_expr (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express op ~[]  as (op []') U (op []'').  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.vrtype () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_unary_expr (vr, code, type, &vrtem0, op0_type);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres (type);
 	  extract_range_from_unary_expr (&vrres, code, type,
 					 &vrtem1, op0_type);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
@@ -1823,7 +2007,7 @@  extract_range_from_unary_expr (value_range *vr,
 	  else if (range_is_null (&vr0))
 	    set_value_range_to_null (vr, type);
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, type);
 	  return;
 	}
 
@@ -1831,8 +2015,8 @@  extract_range_from_unary_expr (value_range *vr,
 	 pointer anti-ranges.  Any remaining anti-ranges at this point
 	 will be integer conversions from SSA names that will be
 	 normalized into VARYING.  For instance: ~[x_55, x_55].  */
-      gcc_assert (vr0.type != VR_ANTI_RANGE
-		  || TREE_CODE (vr0.min) != INTEGER_CST);
+      gcc_assert (vr0.vrtype () != VR_ANTI_RANGE
+		  || TREE_CODE (vr0.min ()) != INTEGER_CST);
 
       /* NOTES: Previously we were returning VARYING for all symbolics, but
 	 we can do better by treating them as [-MIN, +MAX].  For
@@ -1855,10 +2039,10 @@  extract_range_from_unary_expr (value_range *vr,
 	{
 	  tree min = wide_int_to_tree (outer_type, wmin);
 	  tree max = wide_int_to_tree (outer_type, wmax);
-	  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
+	  vr->set_and_canonicalize (VR_RANGE, outer_type, min, max, NULL);
 	}
       else
-	set_value_range_to_varying (vr);
+	set_value_range_to_varying (vr, outer_type);
       return;
     }
   else if (code == ABS_EXPR)
@@ -1872,12 +2056,12 @@  extract_range_from_unary_expr (value_range *vr,
 			 wide_int_to_tree (type, wmin),
 			 wide_int_to_tree (type, wmax), NULL);
       else
-	set_value_range_to_varying (vr);
+	set_value_range_to_varying (vr, type);
       return;
     }
 
   /* For unhandled operations fall back to varying.  */
-  set_value_range_to_varying (vr);
+  set_value_range_to_varying (vr, type);
   return;
 }
 
@@ -1897,39 +2081,39 @@  dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
-  else if (vr->type == VR_UNDEFINED)
+  else if (vr->undefined_p ())
     fprintf (file, "UNDEFINED");
-  else if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
+  else if (vr->vrtype () == VR_RANGE || vr->vrtype () == VR_ANTI_RANGE)
     {
-      tree type = TREE_TYPE (vr->min);
+      tree type = TREE_TYPE (vr->min ());
 
-      fprintf (file, "%s[", (vr->type == VR_ANTI_RANGE) ? "~" : "");
+      fprintf (file, "%s[", (vr->vrtype () == VR_ANTI_RANGE) ? "~" : "");
 
       if (INTEGRAL_TYPE_P (type)
 	  && !TYPE_UNSIGNED (type)
-	  && vrp_val_is_min (vr->min))
+	  && vrp_val_is_min (vr->min ()))
 	fprintf (file, "-INF");
       else
-	print_generic_expr (file, vr->min);
+	print_generic_expr (file, vr->min ());
 
       fprintf (file, ", ");
 
       if (INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_max (vr->max))
+	  && vrp_val_is_max (vr->max ()))
 	fprintf (file, "+INF");
       else
-	print_generic_expr (file, vr->max);
+	print_generic_expr (file, vr->max ());
 
       fprintf (file, "]");
 
-      if (vr->equiv)
+      if (vr->equiv ())
 	{
 	  bitmap_iterator bi;
 	  unsigned i, c = 0;
 
 	  fprintf (file, "  EQUIVALENCES: { ");
 
-	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv, 0, i, bi)
+	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv (), 0, i, bi)
 	    {
 	      print_generic_expr (file, ssa_name (i));
 	      fprintf (file, " ");
@@ -1939,7 +2123,7 @@  dump_value_range (FILE *file, const value_range *vr)
 	  fprintf (file, "} (%u elements)", c);
 	}
     }
-  else if (vr->type == VR_VARYING)
+  else if (vr->varying_p ())
     fprintf (file, "VARYING");
   else
     fprintf (file, "INVALID RANGE");
@@ -1951,14 +2135,7 @@  dump_value_range (FILE *file, const value_range *vr)
 DEBUG_FUNCTION void
 debug_value_range (const value_range *vr)
 {
-  dump_value_range (stderr, vr);
-  fprintf (stderr, "\n");
-}
-
-void
-value_range::dump () const
-{
-  debug_value_range (this);
+  vr->dump ();
 }
 
 
@@ -4202,14 +4379,14 @@  vrp_prop::check_array_ref (location_t location, tree ref,
   if (TREE_CODE (low_sub) == SSA_NAME)
     {
       vr = get_value_range (low_sub);
-      if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
+      if (!vr->undefined_p () && !vr->varying_p ())
         {
-          low_sub = vr->type == VR_RANGE ? vr->max : vr->min;
-          up_sub = vr->type == VR_RANGE ? vr->min : vr->max;
+          low_sub = vr->vrtype () == VR_RANGE ? vr->max () : vr->min ();
+          up_sub = vr->vrtype () == VR_RANGE ? vr->min () : vr->max ();
         }
     }
 
-  if (vr && vr->type == VR_ANTI_RANGE)
+  if (vr && vr->vrtype () == VR_ANTI_RANGE)
     {
       if (up_bound
 	  && TREE_CODE (up_sub) == INTEGER_CST
@@ -4337,21 +4514,20 @@  vrp_prop::check_mem_ref (location_t location, tree ref,
 	break;
 
       vr = get_value_range (varoff);
-      if (!vr || vr->type == VR_UNDEFINED || !vr->min || !vr->max)
+      if (!vr || vr->undefined_p () || vr->varying_p ())
 	break;
 
-      if (TREE_CODE (vr->min) != INTEGER_CST
-          || TREE_CODE (vr->max) != INTEGER_CST)
+      if (!vr->numeric_p ())
         break;
 
-      if (vr->type == VR_RANGE)
+      if (vr->vrtype () == VR_RANGE)
 	{
-	  if (tree_int_cst_lt (vr->min, vr->max))
+	  if (tree_int_cst_lt (vr->min (), vr->max ()))
 	    {
 	      offset_int min
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min ()));
 	      offset_int max
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max ()));
 	      if (min < max)
 		{
 		  offrange[0] += min;
@@ -4969,7 +5145,8 @@  vrp_prop::vrp_initialize ()
 	  if (!stmt_interesting_for_vrp (phi))
 	    {
 	      tree lhs = PHI_RESULT (phi);
-	      set_value_range_to_varying (get_value_range (lhs));
+	      set_value_range_to_varying (get_value_range (lhs),
+					  TREE_TYPE (lhs));
 	      prop_set_simulate_again (phi, false);
 	    }
 	  else
@@ -5123,8 +5300,8 @@  find_case_label_range (gswitch *stmt, tree min, tree max, size_t *min_idx,
 enum ssa_prop_result
 vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 {
-  value_range vr = VR_INITIALIZER;
   tree lhs = gimple_get_lhs (stmt);
+  value_range vr (lhs ? TREE_TYPE (lhs) : NULL);
   extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr);
 
   if (*output_p)
@@ -5140,7 +5317,7 @@  vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 	      fprintf (dump_file, "\n");
 	    }
 
-	  if (vr.type == VR_VARYING)
+	  if (vr.varying_p ())
 	    return SSA_PROP_VARYING;
 
 	  return SSA_PROP_INTERESTING;
@@ -5164,7 +5341,8 @@  vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 	    use_operand_p use_p;
 	    enum ssa_prop_result res = SSA_PROP_VARYING;
 
-	    set_value_range_to_varying (get_value_range (lhs));
+	    set_value_range_to_varying (get_value_range (lhs),
+					TREE_TYPE (lhs));
 
 	    FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
 	      {
@@ -5193,17 +5371,14 @@  vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 		   SSA_PROP_NOT_INTERESTING.  If there are no
 		   {REAL,IMAG}PART_EXPR uses at all,
 		   return SSA_PROP_VARYING.  */
-		value_range new_vr = VR_INITIALIZER;
+		value_range new_vr (TREE_TYPE (lhs));
 		extract_range_basic (&new_vr, use_stmt);
 		const value_range *old_vr = get_value_range (use_lhs);
-		if (old_vr->type != new_vr.type
-		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
-		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
-		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
+		if (*old_vr != new_vr)
 		  res = SSA_PROP_INTERESTING;
 		else
 		  res = SSA_PROP_NOT_INTERESTING;
-		BITMAP_FREE (new_vr.equiv);
+		new_vr.equiv_free ();
 		if (res == SSA_PROP_INTERESTING)
 		  {
 		    *output_p = lhs;
@@ -5814,8 +5989,6 @@  intersect_ranges (enum value_range_type *vr0type,
       *vr0min = vr1min;
       *vr0max = vr1max;
     }
-
-  return;
 }
 
 
@@ -5823,14 +5996,12 @@  intersect_ranges (enum value_range_type *vr0type,
    in *VR0.  This may not be the smallest possible such range.  */
 
 static void
-vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
+vrp_intersect_1 (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
   /* If either range is VR_VARYING the other one wins.  */
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     return;
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       copy_value_range (vr0, vr1);
       return;
@@ -5838,49 +6009,53 @@  vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
 
   /* When either range is VR_UNDEFINED the resulting range is
      VR_UNDEFINED, too.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
-  if (vr1->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
-      set_value_range_to_undefined (vr0);
+      set_value_range_to_undefined (vr0, vr0->type ());
       return;
     }
 
   /* Save the original vr0 so we can return it as conservative intersection
      result when our worker turns things to varying.  */
-  saved = *vr0;
-  intersect_ranges (&vr0->type, &vr0->min, &vr0->max,
-		    vr1->type, vr1->min, vr1->max);
+  value_range saved (*vr0);
+
+  value_range_type vr0type = vr0->vrtype ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  intersect_ranges (&vr0type, &vr0min, &vr0max,
+		    vr1->vrtype (), vr1->min (), vr1->max ());
   /* Make sure to canonicalize the result though as the inversion of a
      VR_RANGE can still be a VR_RANGE.  */
-  set_and_canonicalize_value_range (vr0, vr0->type,
-				    vr0->min, vr0->max, vr0->equiv);
+  vr0->set_and_canonicalize (vr0type, vr0->type (), vr0min, vr0max,
+			     vr0->equiv ());
   /* If that failed, use the saved original VR0.  */
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       *vr0 = saved;
       return;
     }
   /* If the result is VR_UNDEFINED there is no need to mess with
      the equivalencies.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
 
   /* The resulting set of equivalences for range intersection is the union of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_ior_into (vr0->equiv, vr1->equiv);
-  else if (vr1->equiv && !vr0->equiv)
+  if (vr0->equiv () && vr1->equiv () && vr0->equiv () != vr1->equiv ())
+    vr0->equiv_ior (vr1);
+  else if (vr1->equiv () && !vr0->equiv ())
     {
       /* All equivalence bitmaps are allocated from the same obstack.  So
 	 we can use the obstack associated with VR to allocate vr0->equiv.  */
-      vr0->equiv = BITMAP_ALLOC (vr1->equiv->obstack);
-      bitmap_copy (vr0->equiv, vr1->equiv);
+      vr0->set_equiv (BITMAP_ALLOC (vr1->equiv ()->obstack));
+      vr0->equiv_copy (vr1);
     }
 }
 
-void
-vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
+static void
+vrp_intersect (value_range *vr0, const value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -5890,7 +6065,7 @@  vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
       dump_value_range (dump_file, vr1);
       fprintf (dump_file, "\n");
     }
-  vrp_intersect_ranges_1 (vr0, vr1);
+  vrp_intersect_1 (vr0, vr1);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
@@ -5904,38 +6079,40 @@  vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
    may not be the smallest possible such range.  */
 
 static void
-vrp_meet_1 (value_range *vr0, const value_range *vr1)
+vrp_union_1 (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     {
-      set_value_range (vr0, vr1->type, vr1->min, vr1->max, vr1->equiv);
+      vr0->copy_with_equiv_update (vr1);
       return;
     }
 
-  if (vr1->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
       /* VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       /* Nothing to do.  VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     {
-      set_value_range_to_varying (vr0);
+      set_value_range_to_varying (vr0, vr0->type ());
       return;
     }
 
-  saved = *vr0;
-  union_ranges (&vr0->type, &vr0->min, &vr0->max,
-		vr1->type, vr1->min, vr1->max);
-  if (vr0->type == VR_VARYING)
+  value_range saved (*vr0);
+  value_range_type vr0type = vr0->vrtype ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  union_ranges (&vr0type, &vr0min, &vr0max,
+		vr1->vrtype (), vr1->min (), vr1->max ());
+  *vr0 = value_range (vr0type, vr0->type (), vr0min, vr0max);
+  if (vr0->varying_p ())
     {
       /* Failed to find an efficient meet.  Before giving up and setting
 	 the result to VARYING, see if we can at least derive a useful
@@ -5943,33 +6120,32 @@  vrp_meet_1 (value_range *vr0, const value_range *vr1)
       if (range_includes_zero_p (&saved) == 0
 	  && range_includes_zero_p (vr1) == 0)
 	{
-	  set_value_range_to_nonnull (vr0, TREE_TYPE (saved.min));
+	  set_value_range_to_nonnull (vr0, saved.type ());
 
 	  /* Since this meet operation did not result from the meeting of
 	     two equivalent names, VR0 cannot have any equivalences.  */
-	  if (vr0->equiv)
-	    bitmap_clear (vr0->equiv);
+	  vr0->equiv_clear ();
 	  return;
 	}
 
-      set_value_range_to_varying (vr0);
+      set_value_range_to_varying (vr0, vr0->type ());
       return;
     }
-  set_and_canonicalize_value_range (vr0, vr0->type, vr0->min, vr0->max,
-				    vr0->equiv);
-  if (vr0->type == VR_VARYING)
+  vr0->set_and_canonicalize (vr0->vrtype (), vr0->type (),
+			     vr0->min (), vr0->max (), vr0->equiv ());
+  if (vr0->varying_p ())
     return;
 
   /* The resulting set of equivalences is always the intersection of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_and_into (vr0->equiv, vr1->equiv);
-  else if (vr0->equiv && !vr1->equiv)
-    bitmap_clear (vr0->equiv);
+  if (vr0->equiv () != vr1->equiv ())
+    vr0->equiv_and (vr1);
+  else if (!vr1->equiv ())
+    vr0->equiv_clear ();
 }
 
-void
-vrp_meet (value_range *vr0, const value_range *vr1)
+static void
+vrp_union (value_range *vr0, const value_range *vr1)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -5979,7 +6155,7 @@  vrp_meet (value_range *vr0, const value_range *vr1)
       dump_value_range (dump_file, vr1);
       fprintf (dump_file, "\n");
     }
-  vrp_meet_1 (vr0, vr1);
+  vrp_union_1 (vr0, vr1);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
@@ -5988,7 +6164,6 @@  vrp_meet (value_range *vr0, const value_range *vr1)
     }
 }
 
-
 /* Visit all arguments for PHI node PHI that flow through executable
    edges.  If a valid value range can be derived from all the incoming
    value ranges, set a new range for the LHS of PHI.  */
@@ -5997,7 +6172,7 @@  enum ssa_prop_result
 vrp_prop::visit_phi (gphi *phi)
 {
   tree lhs = PHI_RESULT (phi);
-  value_range vr_result = VR_INITIALIZER;
+  value_range vr_result (TREE_TYPE (lhs));
   extract_range_from_phi_node (phi, &vr_result);
   if (update_value_range (lhs, &vr_result))
     {
@@ -6010,7 +6185,7 @@  vrp_prop::visit_phi (gphi *phi)
 	  fprintf (dump_file, "\n");
 	}
 
-      if (vr_result.type == VR_VARYING)
+      if (vr_result.varying_p ())
 	return SSA_PROP_VARYING;
 
       return SSA_PROP_INTERESTING;
@@ -6194,16 +6369,17 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
       op = lhs_of_dominating_assert (op, bb, stmt);
 
       const value_range *vr = vr_values->get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->vrtype () == VR_RANGE)
 	{
 	  size_t i, j;
 	  /* Get the range of labels that contain a part of the operand's
 	     value range.  */
-	  find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+	  find_case_label_range (switch_stmt, vr->min (), vr->max (), &i, &j);
 
 	  /* Is there only one such label?  */
 	  if (i == j)
@@ -6213,10 +6389,11 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	      /* The i'th label will be taken only if the value range of the
 		 operand is entirely within the bounds of this label.  */
 	      if (CASE_HIGH (label) != NULL_TREE
-		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
-		     && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
-		  : (tree_int_cst_equal (CASE_LOW (label), vr->min)
-		     && tree_int_cst_equal (vr->min, vr->max)))
+		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min ()) <= 0
+		     && tree_int_cst_compare (CASE_HIGH (label),
+					      vr->max ()) >= 0)
+		  : (tree_int_cst_equal (CASE_LOW (label), vr->min ())
+		     && tree_int_cst_equal (vr->min (), vr->max ())))
 		return label;
 	    }
 
@@ -6226,7 +6403,7 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	    return gimple_switch_label (switch_stmt, 0);
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->vrtype () == VR_ANTI_RANGE)
 	{
 	  unsigned n = gimple_switch_num_labels (switch_stmt);
 	  tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -6235,10 +6412,12 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	  /* The default label will be taken only if the anti-range of the
 	     operand is entirely outside the bounds of all the (non-default)
 	     case labels.  */
-	  if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+	  if (tree_int_cst_compare (vr->min (), CASE_LOW (min_label)) <= 0
 	      && (CASE_HIGH (max_label) != NULL_TREE
-		  ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
-		  : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+		  ? tree_int_cst_compare (vr->max (),
+					  CASE_HIGH (max_label)) >= 0
+		  : tree_int_cst_compare (vr->max (),
+					  CASE_LOW (max_label)) >= 0))
 	  return gimple_switch_label (switch_stmt, 0);
 	}
 
@@ -6255,11 +6434,12 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	{
 	  edge dummy_e;
 	  tree dummy_tree;
-	  value_range new_vr = VR_INITIALIZER;
+	  value_range new_vr (TREE_TYPE (lhs));
 	  vr_values->extract_range_from_stmt (stmt, &dummy_e,
 					      &dummy_tree, &new_vr);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  tree singleton = new_vr.singleton ();
+	  if (singleton)
+	    return singleton;
 	}
     }
 
@@ -6431,20 +6611,16 @@  vrp_prop::vrp_finalize (bool warn_array_bounds_p)
 	continue;
 
       const value_range *vr = get_value_range (name);
-      if (!name
-	  || (vr->type == VR_VARYING)
-	  || (vr->type == VR_UNDEFINED)
-	  || (TREE_CODE (vr->min) != INTEGER_CST)
-	  || (TREE_CODE (vr->max) != INTEGER_CST))
+      if (!name || !vr->numeric_p ())
 	continue;
 
       if (POINTER_TYPE_P (TREE_TYPE (name))
 	  && range_includes_zero_p (vr) == 0)
 	set_ptr_nonnull (name);
       else if (!POINTER_TYPE_P (TREE_TYPE (name)))
-	set_range_info (name, vr->type,
-			wi::to_wide (vr->min),
-			wi::to_wide (vr->max));
+	set_range_info (name, vr->vrtype (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
     }
 
   /* If we're checking array refs, we want to merge information on
@@ -6636,7 +6812,8 @@  determine_value_range_1 (value_range *vr, tree expr)
 {
   if (BINARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER, vr1 = VR_INITIALIZER;
+      value_range vr0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
+      value_range vr1 (TREE_TYPE (TREE_OPERAND (expr, 1)));
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       determine_value_range_1 (&vr1, TREE_OPERAND (expr, 1));
       extract_range_from_binary_expr_1 (vr, TREE_CODE (expr), TREE_TYPE (expr),
@@ -6644,7 +6821,7 @@  determine_value_range_1 (value_range *vr, tree expr)
     }
   else if (UNARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER;
+      value_range vr0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       extract_range_from_unary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr),
 				     &vr0, TREE_TYPE (TREE_OPERAND (expr, 0)));
@@ -6663,7 +6840,7 @@  determine_value_range_1 (value_range *vr, tree expr)
 	set_value_range (vr, kind, wide_int_to_tree (TREE_TYPE (expr), min),
 			 wide_int_to_tree (TREE_TYPE (expr), max), NULL);
       else
-	set_value_range_to_varying (vr);
+	set_value_range_to_varying (vr, TREE_TYPE (expr));
     }
 }
 
@@ -6673,15 +6850,13 @@  determine_value_range_1 (value_range *vr, tree expr)
 value_range_type
 determine_value_range (tree expr, wide_int *min, wide_int *max)
 {
-  value_range vr = VR_INITIALIZER;
+  value_range vr (TREE_TYPE (expr));
   determine_value_range_1 (&vr, expr);
-  if ((vr.type == VR_RANGE
-       || vr.type == VR_ANTI_RANGE)
-      && !symbolic_range_p (&vr))
+  if (vr.numeric_p ())
     {
-      *min = wi::to_wide (vr.min);
-      *max = wi::to_wide (vr.max);
-      return vr.type;
+      *min = wi::to_wide (vr.min ());
+      *max = wi::to_wide (vr.max ());
+      return vr.vrtype ();
     }
 
   return VR_VARYING;
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index 655cf055f0a..04e0d0cb4a6 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -27,35 +27,140 @@  enum value_range_type { VR_UNDEFINED, VR_RANGE,
 
 /* Range of values that can be associated with an SSA_NAME after VRP
    has executed.  */
-struct GTY((for_user)) value_range
+class GTY((for_user)) value_range
 {
-  /* Lattice value represented by this range.  */
-  enum value_range_type type;
+ public:
+  value_range ();
+  value_range (tree type);
+  value_range (value_range_type, tree type, tree, tree, bitmap = NULL);
+  bool operator== (const value_range &) const;
+  bool operator!= (const value_range &) const;
+  void intersect (const value_range *);
+  void union_ (const value_range *);
+  /* Like operator== but ignore equivalence bitmap.  */
+  bool ignore_equivs_equal_p (const value_range &) const;
+  /* Like a operator= but update equivalence bitmap efficiently.  */
+  void copy_with_equiv_update (const value_range *);
+
+  /* Types of value ranges.  */
+  bool undefined_p () const;
+  bool varying_p () const;
+  bool symbolic_p () const;
+  bool numeric_p () const;
+  void set_undefined (tree = NULL);
+  void set_varying (tree = NULL);
+
+  /* Equivalence bitmap methods.  */
+  bitmap equiv () const;
+  void set_equiv (bitmap);
+  void equiv_free ();
+  void equiv_copy (const value_range *);
+  void equiv_clear ();
+  void equiv_and (const value_range *);
+  void equiv_ior (const value_range *);
+
+  /* Misc methods.  */
+  tree type () const;
+  bool null_p () const;
+  bool may_contain_p (tree) const;
+  tree singleton () const;
+  void set_and_canonicalize (enum value_range_type, tree, tree, tree, bitmap);
+  void dump () const;
 
-  /* Minimum and maximum values represented by this range.  These
-     values should be interpreted as follows:
+  /* Temporary accessors that should eventually be removed.  */
+  enum value_range_type vrtype () const;
+  tree min () const;
+  tree max () const;
+
+ private:
+  void set (value_range_type, tree type, tree, tree, bitmap);
+  void check ();
+  bool equal_p (const value_range &, bool ignore_equivs) const;
+
+  enum value_range_type m_vrtype;
+ public:
+  /* These should be private, but GTY is a piece of crap.  */
+  tree m_min;
+  tree m_max;
+  tree m_type;
+  /* Set of SSA names whose value ranges are equivalent to this one.
+     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
+  bitmap m_equiv;
+};
 
-	- If TYPE is VR_UNDEFINED or VR_VARYING then MIN and MAX must
-	  be NULL.
+inline
+value_range::value_range ()
+{
+  m_type = m_min = m_max = NULL;
+  m_vrtype = VR_UNDEFINED;
+  m_equiv = NULL;
+}
 
-	- If TYPE == VR_RANGE then MIN holds the minimum value and
-	  MAX holds the maximum value of the range [MIN, MAX].
+inline
+value_range::value_range (tree type)
+{
+  m_vrtype = VR_UNDEFINED;
+  m_min = m_max = NULL;
+  m_equiv = NULL;
+  m_type = type;
+}
+
+inline value_range_type
+value_range::vrtype () const
+{
+  return m_vrtype;
+}
 
-	- If TYPE == ANTI_RANGE the variable is known to NOT
-	  take any values in the range [MIN, MAX].  */
-  tree min;
-  tree max;
+inline tree
+value_range::type () const
+{
+  return m_type;
+}
 
-  /* Set of SSA names whose value ranges are equivalent to this one.
-     This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
-  bitmap equiv;
+inline bitmap
+value_range::equiv () const
+{
+  return m_equiv;
+}
 
-  /* Dump value range to stderr.  */
-  void dump () const;
-};
+inline tree
+value_range::min () const
+{
+  return m_min;
+}
+
+inline tree
+value_range::max () const
+{
+  return m_max;
+}
+
+inline bool
+value_range::varying_p () const
+{
+  return m_vrtype == VR_VARYING;
+}
+
+inline bool
+value_range::undefined_p () const
+{
+  return m_vrtype == VR_UNDEFINED;
+}
+
+inline void
+value_range::set_equiv (bitmap b)
+{
+  m_equiv = b;
+}
+
+inline bool
+value_range::null_p () const
+{
+  return (m_vrtype == VR_RANGE
+	  && integer_zerop (m_min)
+	  && integer_zerop (m_max));
+}
 
-extern void vrp_intersect_ranges (value_range *vr0, const value_range *vr1);
-extern void vrp_meet (value_range *vr0, const value_range *vr1);
 extern void dump_value_range (FILE *, const value_range *);
 extern void extract_range_from_unary_expr (value_range *vr,
 					   enum tree_code code,
@@ -85,19 +190,17 @@  struct assert_info
 extern void register_edge_assert_for (tree, edge, enum tree_code,
 				      tree, tree, vec<assert_info> &);
 extern bool stmt_interesting_for_vrp (gimple *);
-extern void set_value_range_to_varying (value_range *);
+extern void set_value_range_to_varying (value_range *, tree);
 extern bool range_includes_zero_p (const value_range *);
 extern bool infer_value_range (gimple *, tree, tree_code *, tree *);
 
 extern void set_value_range_to_nonnull (value_range *, tree);
 extern void set_value_range (value_range *, enum value_range_type, tree,
 			     tree, bitmap);
-extern void set_and_canonicalize_value_range (value_range *,
-					      enum value_range_type,
-					      tree, tree, bitmap);
+extern void set_value_range (value_range *, tree, enum value_range_type, tree,
+			     tree, bitmap);
 extern bool vrp_bitmap_equal_p (const_bitmap, const_bitmap);
 extern tree value_range_constant_singleton (const value_range *);
-extern bool symbolic_range_p (const value_range *);
 extern int compare_values (tree, tree);
 extern int compare_values_warnv (tree, tree, bool *);
 extern bool vrp_val_is_min (const_tree);
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 32392a11618..984cc16ddc0 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -55,7 +55,7 @@  static inline void
 set_value_range_to_nonnegative (value_range *vr, tree type)
 {
   tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_RANGE, zero, vrp_val_max (type), vr->equiv);
+  set_value_range (vr, VR_RANGE, zero, vrp_val_max (type), vr->equiv ());
 }
 
 /* Set value range VR to a range of a truthvalue of type TYPE.  */
@@ -64,11 +64,11 @@  static inline void
 set_value_range_to_truthvalue (value_range *vr, tree type)
 {
   if (TYPE_PRECISION (type) == 1)
-    set_value_range_to_varying (vr);
+    set_value_range_to_varying (vr, type);
   else
     set_value_range (vr, VR_RANGE,
 		     build_int_cst (type, 0), build_int_cst (type, 1),
-		     vr->equiv);
+		     vr->equiv ());
 }
 
 
@@ -80,8 +80,8 @@  set_value_range_to_truthvalue (value_range *vr, tree type)
 value_range *
 vr_values::get_value_range (const_tree var)
 {
-  static const value_range vr_const_varying
-    = { VR_VARYING, NULL_TREE, NULL_TREE, NULL };
+  static const value_range vr_const_varying (VR_VARYING, TREE_TYPE (var),
+					     NULL, NULL);
   value_range *vr;
   tree sym;
   unsigned ver = SSA_NAME_VERSION (var);
@@ -106,10 +106,7 @@  vr_values::get_value_range (const_tree var)
 
   /* Create a default value range.  */
   vr_value[ver] = vr = vrp_value_range_pool.allocate ();
-  memset (vr, 0, sizeof (*vr));
-
-  /* Defer allocating the equivalence set.  */
-  vr->equiv = NULL;
+  *vr = value_range (TREE_TYPE (var));
 
   /* If VAR is a default definition of a parameter, the variable can
      take any value in VAR's type.  */
@@ -135,10 +132,10 @@  vr_values::get_value_range (const_tree var)
 				 wide_int_to_tree (TREE_TYPE (var), max),
 				 NULL);
 	      else
-		set_value_range_to_varying (vr);
+		set_value_range_to_varying (vr, TREE_TYPE (var));
 	    }
 	  else
-	    set_value_range_to_varying (vr);
+	    set_value_range_to_varying (vr, TREE_TYPE (sym));
 	}
       else if (TREE_CODE (sym) == RESULT_DECL
 	       && DECL_BY_REFERENCE (sym))
@@ -159,8 +156,8 @@  vr_values::set_defs_to_varying (gimple *stmt)
     {
       value_range *vr = get_value_range (def);
       /* Avoid writing to vr_const_varying get_value_range may return.  */
-      if (vr->type != VR_VARYING)
-	set_value_range_to_varying (vr);
+      if (!vr->varying_p ())
+	set_value_range_to_varying (vr, vr->type ());
     }
 }
 
@@ -191,18 +188,19 @@  vr_values::update_value_range (const_tree var, value_range *new_vr)
 	  tree nr_min, nr_max;
 	  nr_min = wide_int_to_tree (TREE_TYPE (var), min);
 	  nr_max = wide_int_to_tree (TREE_TYPE (var), max);
-	  value_range nr = VR_INITIALIZER;
-	  set_and_canonicalize_value_range (&nr, rtype, nr_min, nr_max, NULL);
-	  vrp_intersect_ranges (new_vr, &nr);
+	  value_range nr (TREE_TYPE (var));
+	  nr.set_and_canonicalize (rtype, TREE_TYPE (var), nr_min, nr_max,
+				   NULL);
+	  new_vr->intersect (&nr);
 	}
     }
 
   /* Update the value range, if necessary.  */
   old_vr = get_value_range (var);
-  is_new = old_vr->type != new_vr->type
-	   || !vrp_operand_equal_p (old_vr->min, new_vr->min)
-	   || !vrp_operand_equal_p (old_vr->max, new_vr->max)
-	   || !vrp_bitmap_equal_p (old_vr->equiv, new_vr->equiv);
+  is_new = old_vr->vrtype () != new_vr->vrtype ()
+	   || !vrp_operand_equal_p (old_vr->min (), new_vr->min ())
+	   || !vrp_operand_equal_p (old_vr->max (), new_vr->max ())
+	   || !vrp_bitmap_equal_p (old_vr->equiv (), new_vr->equiv ());
 
   if (is_new)
     {
@@ -212,19 +210,20 @@  vr_values::update_value_range (const_tree var, value_range *new_vr)
 	 the same.  We may not have is_new when transitioning to
 	 UNDEFINED.  If old_vr->type is VARYING, we shouldn't be
 	 called.  */
-      if (new_vr->type == VR_UNDEFINED)
+      if (new_vr->undefined_p ())
 	{
-	  BITMAP_FREE (new_vr->equiv);
-	  set_value_range_to_varying (old_vr);
-	  set_value_range_to_varying (new_vr);
+	  new_vr->equiv_free ();
+	  set_value_range_to_varying (old_vr, TREE_TYPE (var));
+	  set_value_range_to_varying (new_vr, TREE_TYPE (var));
 	  return true;
 	}
       else
-	set_value_range (old_vr, new_vr->type, new_vr->min, new_vr->max,
-			 new_vr->equiv);
+	set_value_range (old_vr, new_vr->type (), new_vr->vrtype (),
+			 new_vr->min (), new_vr->max (),
+			 new_vr->equiv ());
     }
 
-  BITMAP_FREE (new_vr->equiv);
+  new_vr->equiv_free ();
 
   return is_new;
 }
@@ -233,17 +232,19 @@  vr_values::update_value_range (const_tree var, value_range *new_vr)
 /* Add VAR and VAR's equivalence set to EQUIV.  This is the central
    point where equivalence processing can be turned on/off.  */
 
-void
-vr_values::add_equivalence (bitmap *equiv, const_tree var)
+bitmap
+vr_values::add_equivalence (bitmap equiv, const_tree var)
 {
   unsigned ver = SSA_NAME_VERSION (var);
   value_range *vr = get_value_range (var);
+  bitmap ret = equiv;
 
-  if (*equiv == NULL)
-    *equiv = BITMAP_ALLOC (&vrp_equiv_obstack);
-  bitmap_set_bit (*equiv, ver);
-  if (vr && vr->equiv)
-    bitmap_ior_into (*equiv, vr->equiv);
+  if (ret == NULL)
+    ret = BITMAP_ALLOC (&vrp_equiv_obstack);
+  bitmap_set_bit (ret, ver);
+  if (vr && vr->equiv ())
+    bitmap_ior_into (ret, vr->equiv ());
+  return ret;
 }
 
 /* Return true if value range VR involves exactly one symbol SYM.  */
@@ -254,16 +255,16 @@  symbolic_range_based_on_p (value_range *vr, const_tree sym)
   bool neg, min_has_symbol, max_has_symbol;
   tree inv;
 
-  if (is_gimple_min_invariant (vr->min))
+  if (is_gimple_min_invariant (vr->min ()))
     min_has_symbol = false;
-  else if (get_single_symbol (vr->min, &neg, &inv) == sym)
+  else if (get_single_symbol (vr->min (), &neg, &inv) == sym)
     min_has_symbol = true;
   else
     return false;
 
-  if (is_gimple_min_invariant (vr->max))
+  if (is_gimple_min_invariant (vr->max ()))
     max_has_symbol = false;
-  else if (get_single_symbol (vr->max, &neg, &inv) == sym)
+  else if (get_single_symbol (vr->max (), &neg, &inv) == sym)
     max_has_symbol = true;
   else
     return false;
@@ -403,9 +404,9 @@  vr_values::op_with_boolean_value_range_p (tree op)
     return false;
 
   vr = get_value_range (op);
-  return (vr->type == VR_RANGE
-	  && integer_zerop (vr->min)
-	  && integer_onep (vr->max));
+  return (vr->vrtype () == VR_RANGE
+	  && integer_zerop (vr->min ())
+	  && integer_onep (vr->max ()));
 }
 
 /* Extract value range information for VAR when (OP COND_CODE LIMIT) is
@@ -427,7 +428,7 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
   if ((POINTER_TYPE_P (type) && cond_code != NE_EXPR && cond_code != EQ_EXPR)
       || limit == var)
     {
-      set_value_range_to_varying (vr_p);
+      set_value_range_to_varying (vr_p, type);
       return;
     }
 
@@ -438,12 +439,13 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 
   /* LIMIT's range is only interesting if it has any useful information.  */
   if (! limit_vr
-      || limit_vr->type == VR_UNDEFINED
-      || limit_vr->type == VR_VARYING
-      || (symbolic_range_p (limit_vr)
-	  && ! (limit_vr->type == VR_RANGE
-		&& (limit_vr->min == limit_vr->max
-		    || operand_equal_p (limit_vr->min, limit_vr->max, 0)))))
+      || limit_vr->undefined_p ()
+      || limit_vr->varying_p ()
+      || (limit_vr->symbolic_p ()
+	  && ! (limit_vr->vrtype () == VR_RANGE
+		&& (limit_vr->min () == limit_vr->max ()
+		    || operand_equal_p (limit_vr->min (),
+					limit_vr->max (), 0)))))
     limit_vr = NULL;
 
   /* Initially, the new range has the same set of equivalences of
@@ -451,8 +453,8 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
      value.  Since assertions may be chained via mutually exclusive
      predicates, we will need to trim the set of equivalences before
      we are done.  */
-  gcc_assert (vr_p->equiv == NULL);
-  add_equivalence (&vr_p->equiv, var);
+  gcc_assert (vr_p->equiv () == NULL);
+  vr_p->set_equiv (add_equivalence (vr_p->equiv (), var));
 
   /* Extract a new range based on the asserted comparison for VAR and
      LIMIT's value range.  Notice that if LIMIT has an anti-range, we
@@ -488,14 +490,14 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
       max = force_fit_type (TREE_TYPE (var), wi::to_widest (max), 0, false);
 
       /* We can transform a max, min range to an anti-range or
-         vice-versa.  Use set_and_canonicalize_value_range which does
-	 this for us.  */
+         vice-versa.  Use set_and_canonicalize which does this for
+         us.  */
       if (cond_code == LE_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_RANGE,
-					  min, max, vr_p->equiv);
+        vr_p->set_and_canonicalize (VR_RANGE, TREE_TYPE (min), min, max,
+				    vr_p->equiv ());
       else if (cond_code == GT_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					  min, max, vr_p->equiv);
+        vr_p->set_and_canonicalize (VR_ANTI_RANGE, TREE_TYPE (min), min, max,
+				    vr_p->equiv ());
       else
 	gcc_unreachable ();
     }
@@ -505,9 +507,9 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 
       if (limit_vr)
 	{
-	  range_type = limit_vr->type;
-	  min = limit_vr->min;
-	  max = limit_vr->max;
+	  range_type = limit_vr->vrtype ();
+	  min = limit_vr->min ();
+	  max = limit_vr->max ();
 	}
       else
 	{
@@ -516,13 +518,13 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	  max = limit;
 	}
 
-      set_value_range (vr_p, range_type, min, max, vr_p->equiv);
+      set_value_range (vr_p, range_type, min, max, vr_p->equiv ());
 
       /* When asserting the equality VAR == LIMIT and LIMIT is another
 	 SSA name, the new range will also inherit the equivalence set
 	 from LIMIT.  */
       if (TREE_CODE (limit) == SSA_NAME)
-	add_equivalence (&vr_p->equiv, limit);
+	vr_p->set_equiv (add_equivalence (vr_p->equiv (), limit));
     }
   else if (cond_code == NE_EXPR)
     {
@@ -547,11 +549,11 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	 (i.e., LIMIT_VR->MIN == LIMIT_VR->MAX).  In that case,
 	 build the anti-range ~[LIMIT_VR->MIN, LIMIT_VR->MAX].  */
       if (limit_vr
-	  && limit_vr->type == VR_RANGE
-	  && compare_values (limit_vr->min, limit_vr->max) == 0)
+	  && limit_vr->vrtype () == VR_RANGE
+	  && compare_values (limit_vr->min (), limit_vr->max ()) == 0)
 	{
-	  min = limit_vr->min;
-	  max = limit_vr->max;
+	  min = limit_vr->min ();
+	  max = limit_vr->max ();
 	}
       else
 	{
@@ -567,21 +569,21 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	  && vrp_val_is_max (max))
 	min = max = limit;
 
-      set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					min, max, vr_p->equiv);
+      vr_p->set_and_canonicalize (VR_ANTI_RANGE, TREE_TYPE (min), min, max,
+				  vr_p->equiv ());
     }
   else if (cond_code == LE_EXPR || cond_code == LT_EXPR)
     {
       min = TYPE_MIN_VALUE (type);
 
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+      if (limit_vr == NULL || limit_vr->vrtype () == VR_ANTI_RANGE)
 	max = limit;
       else
 	{
 	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
 	     range [MIN, N2] for LE_EXPR and [MIN, N2 - 1] for
 	     LT_EXPR.  */
-	  max = limit_vr->max;
+	  max = limit_vr->max ();
 	}
 
       /* If the maximum value forces us to be out of bounds, simply punt.
@@ -589,7 +591,7 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	 all should be optimized away above us.  */
       if (cond_code == LT_EXPR
 	  && compare_values (max, min) == 0)
-	set_value_range_to_varying (vr_p);
+	set_value_range_to_varying (vr_p, type);
       else
 	{
 	  /* For LT_EXPR, we create the range [MIN, MAX - 1].  */
@@ -607,21 +609,21 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 		TREE_NO_WARNING (max) = 1;
 	    }
 
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv ());
 	}
     }
   else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
     {
       max = TYPE_MAX_VALUE (type);
 
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+      if (limit_vr == NULL || limit_vr->vrtype () == VR_ANTI_RANGE)
 	min = limit;
       else
 	{
 	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
 	     range [N1, MAX] for GE_EXPR and [N1 + 1, MAX] for
 	     GT_EXPR.  */
-	  min = limit_vr->min;
+	  min = limit_vr->min ();
 	}
 
       /* If the minimum value forces us to be out of bounds, simply punt.
@@ -629,7 +631,7 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 	 all should be optimized away above us.  */
       if (cond_code == GT_EXPR
 	  && compare_values (min, max) == 0)
-	set_value_range_to_varying (vr_p);
+	set_value_range_to_varying (vr_p, type);
       else
 	{
 	  /* For GT_EXPR, we create the range [MIN + 1, MAX].  */
@@ -647,14 +649,14 @@  vr_values::extract_range_for_var_from_comparison_expr (tree var,
 		TREE_NO_WARNING (min) = 1;
 	    }
 
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv ());
 	}
     }
   else
     gcc_unreachable ();
 
   /* Finally intersect the new range with what we already know about var.  */
-  vrp_intersect_ranges (vr_p, get_value_range (var));
+  vr_p->intersect (get_value_range (var));
 }
 
 /* Extract value range information from an ASSERT_EXPR EXPR and store
@@ -711,12 +713,12 @@  vr_values::extract_range_from_ssa_name (value_range *vr, tree var)
 {
   value_range *var_vr = get_value_range (var);
 
-  if (var_vr->type != VR_VARYING)
+  if (!var_vr->varying_p ())
     copy_value_range (vr, var_vr);
   else
     set_value_range (vr, VR_RANGE, var, var, NULL);
 
-  add_equivalence (&vr->equiv, var);
+  vr->set_equiv (add_equivalence (vr->equiv (), var));
 }
 
 /* Extract range information from a binary expression OP0 CODE OP1 based on
@@ -728,8 +730,7 @@  vr_values::extract_range_from_binary_expr (value_range *vr,
 					   enum tree_code code,
 					   tree expr_type, tree op0, tree op1)
 {
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
+  value_range vr0 (expr_type), vr1 (expr_type);
 
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
@@ -738,32 +739,28 @@  vr_values::extract_range_from_binary_expr (value_range *vr,
   else if (is_gimple_min_invariant (op0))
     set_value_range_to_value (&vr0, op0, NULL);
   else
-    set_value_range_to_varying (&vr0);
+    set_value_range_to_varying (&vr0, expr_type);
 
   if (TREE_CODE (op1) == SSA_NAME)
     vr1 = *(get_value_range (op1));
   else if (is_gimple_min_invariant (op1))
     set_value_range_to_value (&vr1, op1, NULL);
   else
-    set_value_range_to_varying (&vr1);
+    set_value_range_to_varying (&vr1, expr_type);
 
   /* If one argument is varying, we can sometimes still deduce a
      range for the output: any + [3, +INF] is in [MIN+3, +INF].  */
   if (INTEGRAL_TYPE_P (TREE_TYPE (op0))
       && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)))
     {
-      if (vr0.type == VR_VARYING && vr1.type != VR_VARYING)
-	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = vrp_val_min (expr_type);
-	  vr0.max = vrp_val_max (expr_type);
-	}
-      else if (vr1.type == VR_VARYING && vr0.type != VR_VARYING)
-	{
-	  vr1.type = VR_RANGE;
-	  vr1.min = vrp_val_min (expr_type);
-	  vr1.max = vrp_val_max (expr_type);
-	}
+      if (vr0.varying_p () && !vr1.varying_p ())
+	vr0 = value_range (VR_RANGE, vr0.type (),
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type));
+      else if (vr1.varying_p () && !vr0.varying_p ())
+	vr1 = value_range (VR_RANGE, vr1.type (),
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type));
     }
 
   extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
@@ -773,7 +770,7 @@  vr_values::extract_range_from_binary_expr (value_range *vr,
      n = def - arg
      Here the range for n can be set to [0, PTRDIFF_MAX - 1]. */
 
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && code == POINTER_DIFF_EXPR
       && TREE_CODE (op0) == SSA_NAME
       && TREE_CODE (op1) == SSA_NAME)
@@ -806,21 +803,21 @@  vr_values::extract_range_from_binary_expr (value_range *vr,
      symbolic comparison.  When a bound of the range of the first operand
      is invariant, we set the corresponding bound of the new range to INF
      in order to avoid recursing on the range of the second operand.  */
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == PLUS_EXPR || code == MINUS_EXPR)
       && TREE_CODE (op1) == SSA_NAME
-      && vr0.type == VR_RANGE
+      && vr0.vrtype () == VR_RANGE
       && symbolic_range_based_on_p (&vr0, op1))
     {
       const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr1 = VR_INITIALIZER;
+      value_range n_vr1 (expr_type);
 
       /* Try with VR0 and [-INF, OP1].  */
-      if (is_gimple_min_invariant (minus_p ? vr0.max : vr0.min))
+      if (is_gimple_min_invariant (minus_p ? vr0.max () : vr0.min ()))
 	set_value_range (&n_vr1, VR_RANGE, vrp_val_min (expr_type), op1, NULL);
 
       /* Try with VR0 and [OP1, +INF].  */
-      else if (is_gimple_min_invariant (minus_p ? vr0.min : vr0.max))
+      else if (is_gimple_min_invariant (minus_p ? vr0.min () : vr0.max ()))
 	set_value_range (&n_vr1, VR_RANGE, op1, vrp_val_max (expr_type), NULL);
 
       /* Try with VR0 and [OP1, OP1].  */
@@ -830,21 +827,21 @@  vr_values::extract_range_from_binary_expr (value_range *vr,
       extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1);
     }
 
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == PLUS_EXPR || code == MINUS_EXPR)
       && TREE_CODE (op0) == SSA_NAME
-      && vr1.type == VR_RANGE
+      && vr1.vrtype () == VR_RANGE
       && symbolic_range_based_on_p (&vr1, op0))
     {
       const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr0 = VR_INITIALIZER;
+      value_range n_vr0 (expr_type);
 
       /* Try with [-INF, OP0] and VR1.  */
-      if (is_gimple_min_invariant (minus_p ? vr1.max : vr1.min))
+      if (is_gimple_min_invariant (minus_p ? vr1.max () : vr1.min ()))
 	set_value_range (&n_vr0, VR_RANGE, vrp_val_min (expr_type), op0, NULL);
 
       /* Try with [OP0, +INF] and VR1.  */
-      else if (is_gimple_min_invariant (minus_p ? vr1.min : vr1.max))
+      else if (is_gimple_min_invariant (minus_p ? vr1.min (): vr1.max ()))
 	set_value_range (&n_vr0, VR_RANGE, op0, vrp_val_max (expr_type), NULL);
 
       /* Try with [OP0, OP0] and VR1.  */
@@ -858,15 +855,15 @@  vr_values::extract_range_from_binary_expr (value_range *vr,
      op1's range is ~[op0,op0] or vice-versa, then we
      can derive a non-null range.  This happens often for
      pointer subtraction.  */
-  if (vr->type == VR_VARYING
+  if (vr->varying_p ()
       && (code == MINUS_EXPR || code == POINTER_DIFF_EXPR)
       && TREE_CODE (op0) == SSA_NAME
-      && ((vr0.type == VR_ANTI_RANGE
-	   && vr0.min == op1
-	   && vr0.min == vr0.max)
-	  || (vr1.type == VR_ANTI_RANGE
-	      && vr1.min == op0
-	      && vr1.min == vr1.max)))
+      && ((vr0.vrtype () == VR_ANTI_RANGE
+	   && vr0.min () == op1
+	   && vr0.min () == vr0.max ())
+	  || (vr1.vrtype () == VR_ANTI_RANGE
+	      && vr1.min () == op0
+	      && vr1.min () == vr1.max ())))
       set_value_range_to_nonnull (vr, expr_type);
 }
 
@@ -878,7 +875,7 @@  void
 vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code,
 					  tree type, tree op0)
 {
-  value_range vr0 = VR_INITIALIZER;
+  value_range vr0 (TREE_TYPE (op0));
 
   /* Get value ranges for the operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
@@ -887,7 +884,7 @@  vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code,
   else if (is_gimple_min_invariant (op0))
     set_value_range_to_value (&vr0, op0, NULL);
   else
-    set_value_range_to_varying (&vr0);
+    set_value_range_to_varying (&vr0, TREE_TYPE (op0));
 
   ::extract_range_from_unary_expr (vr, code, type, &vr0, TREE_TYPE (op0));
 }
@@ -899,31 +896,29 @@  vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code,
 void
 vr_values::extract_range_from_cond_expr (value_range *vr, gassign *stmt)
 {
-  tree op0, op1;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
-  op0 = gimple_assign_rhs2 (stmt);
+  tree op0 = gimple_assign_rhs2 (stmt);
+  value_range vr0 (TREE_TYPE (op0));
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
   else if (is_gimple_min_invariant (op0))
     set_value_range_to_value (&vr0, op0, NULL);
   else
-    set_value_range_to_varying (&vr0);
+    set_value_range_to_varying (&vr0, TREE_TYPE (op0));
 
-  op1 = gimple_assign_rhs3 (stmt);
+  tree op1 = gimple_assign_rhs3 (stmt);
+  value_range vr1 (TREE_TYPE (op1));
   if (TREE_CODE (op1) == SSA_NAME)
     vr1 = *(get_value_range (op1));
   else if (is_gimple_min_invariant (op1))
     set_value_range_to_value (&vr1, op1, NULL);
   else
-    set_value_range_to_varying (&vr1);
+    set_value_range_to_varying (&vr1, TREE_TYPE (op1));
 
   /* The resulting value range is the union of the operand ranges */
   copy_value_range (vr, &vr0);
-  vrp_meet (vr, &vr1);
+  vr->union_ (&vr1);
 }
 
 
@@ -946,9 +941,9 @@  vr_values::extract_range_from_comparison (value_range *vr, enum tree_code code,
 	 type.  */
       val = fold_convert (type, val);
       if (is_gimple_min_invariant (val))
-	set_value_range_to_value (vr, val, vr->equiv);
+	set_value_range_to_value (vr, val, vr->equiv ());
       else
-	set_value_range (vr, VR_RANGE, val, val, vr->equiv);
+	set_value_range (vr, VR_RANGE, val, val, vr->equiv ());
     }
   else
     /* The result of a comparison is always true or false.  */
@@ -965,45 +960,47 @@  bool
 vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
 					 tree op0, tree op1, bool *ovf)
 {
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
+  value_range vr0 (type);
+  value_range vr1 (type);
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *get_value_range (op0);
   else if (TREE_CODE (op0) == INTEGER_CST)
     set_value_range_to_value (&vr0, op0, NULL);
   else
-    set_value_range_to_varying (&vr0);
+    set_value_range_to_varying (&vr0, TREE_TYPE (op0));
 
   if (TREE_CODE (op1) == SSA_NAME)
     vr1 = *get_value_range (op1);
   else if (TREE_CODE (op1) == INTEGER_CST)
     set_value_range_to_value (&vr1, op1, NULL);
   else
-    set_value_range_to_varying (&vr1);
+    set_value_range_to_varying (&vr1, TREE_TYPE (op1));
 
+  tree vr0min = vr0.min (), vr0max = vr0.max ();
+  tree vr1min = vr1.min (), vr1max = vr1.max ();
   if (!range_int_cst_p (&vr0)
-      || TREE_OVERFLOW (vr0.min)
-      || TREE_OVERFLOW (vr0.max))
+      || TREE_OVERFLOW (vr0min)
+      || TREE_OVERFLOW (vr0max))
     {
-      vr0.min = vrp_val_min (TREE_TYPE (op0));
-      vr0.max = vrp_val_max (TREE_TYPE (op0));
+      vr0min = vrp_val_min (TREE_TYPE (op0));
+      vr0max = vrp_val_max (TREE_TYPE (op0));
     }
   if (!range_int_cst_p (&vr1)
-      || TREE_OVERFLOW (vr1.min)
-      || TREE_OVERFLOW (vr1.max))
+      || TREE_OVERFLOW (vr1min)
+      || TREE_OVERFLOW (vr1max))
     {
-      vr1.min = vrp_val_min (TREE_TYPE (op1));
-      vr1.max = vrp_val_max (TREE_TYPE (op1));
+      vr1min = vrp_val_min (TREE_TYPE (op1));
+      vr1max = vrp_val_max (TREE_TYPE (op1));
     }
-  *ovf = arith_overflowed_p (subcode, type, vr0.min,
-			     subcode == MINUS_EXPR ? vr1.max : vr1.min);
-  if (arith_overflowed_p (subcode, type, vr0.max,
-			  subcode == MINUS_EXPR ? vr1.min : vr1.max) != *ovf)
+  *ovf = arith_overflowed_p (subcode, type, vr0min,
+			     subcode == MINUS_EXPR ? vr1max : vr1min);
+  if (arith_overflowed_p (subcode, type, vr0max,
+			  subcode == MINUS_EXPR ? vr1min : vr1max) != *ovf)
     return false;
   if (subcode == MULT_EXPR)
     {
-      if (arith_overflowed_p (subcode, type, vr0.min, vr1.max) != *ovf
-	  || arith_overflowed_p (subcode, type, vr0.max, vr1.min) != *ovf)
+      if (arith_overflowed_p (subcode, type, vr0min, vr1max) != *ovf
+	  || arith_overflowed_p (subcode, type, vr0max, vr1min) != *ovf)
 	return false;
     }
   if (*ovf)
@@ -1016,10 +1013,10 @@  vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type,
       widest_int wmin, wmax;
       widest_int w[4];
       int i;
-      w[0] = wi::to_widest (vr0.min);
-      w[1] = wi::to_widest (vr0.max);
-      w[2] = wi::to_widest (vr1.min);
-      w[3] = wi::to_widest (vr1.max);
+      w[0] = wi::to_widest (vr0min);
+      w[1] = wi::to_widest (vr0max);
+      w[2] = wi::to_widest (vr1min);
+      w[3] = wi::to_widest (vr1max);
       for (i = 0; i < 4; i++)
 	{
 	  widest_int wt;
@@ -1113,11 +1110,11 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		mini = 1;
 	      /* If some high bits are known to be zero,
 		 we can decrease the maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST
-		  && !operand_less_p (vr0->min,
-				      build_zero_cst (TREE_TYPE (vr0->min))))
-		maxi = tree_floor_log2 (vr0->max) + 1;
+	      if (vr0->vrtype () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST
+		  && !operand_less_p (vr0->min (),
+				      build_zero_cst (TREE_TYPE (vr0->min ()))))
+		maxi = tree_floor_log2 (vr0->max ()) + 1;
 	    }
 	  goto bitop_builtin;
 	  /* __builtin_parity* returns [0, 1].  */
@@ -1148,15 +1145,15 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	      value_range *vr0 = get_value_range (arg);
 	      /* From clz of VR_RANGE minimum we can compute
 		 result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->min) == INTEGER_CST)
+	      if (vr0->vrtype () == VR_RANGE
+		  && TREE_CODE (vr0->min ()) == INTEGER_CST)
 		{
-		  maxi = prec - 1 - tree_floor_log2 (vr0->min);
+		  maxi = prec - 1 - tree_floor_log2 (vr0->min ());
 		  if (maxi != prec)
 		    mini = 0;
 		}
-	      else if (vr0->type == VR_ANTI_RANGE
-		       && integer_zerop (vr0->min))
+	      else if (vr0->vrtype () == VR_ANTI_RANGE
+		       && integer_zerop (vr0->min ()))
 		{
 		  maxi = prec - 1;
 		  mini = 0;
@@ -1165,10 +1162,10 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		break;
 	      /* From clz of VR_RANGE maximum we can compute
 		 result minimum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
+	      if (vr0->vrtype () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST)
 		{
-		  mini = prec - 1 - tree_floor_log2 (vr0->max);
+		  mini = prec - 1 - tree_floor_log2 (vr0->max ());
 		  if (mini == prec)
 		    break;
 		}
@@ -1204,20 +1201,20 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	    {
 	      value_range *vr0 = get_value_range (arg);
 	      /* If arg is non-zero, then use [0, prec - 1].  */
-	      if ((vr0->type == VR_RANGE
-		   && integer_nonzerop (vr0->min))
-		  || (vr0->type == VR_ANTI_RANGE
-		      && integer_zerop (vr0->min)))
+	      if ((vr0->vrtype () == VR_RANGE
+		   && integer_nonzerop (vr0->min ()))
+		  || (vr0->vrtype () == VR_ANTI_RANGE
+		      && integer_zerop (vr0->min ())))
 		{
 		  mini = 0;
 		  maxi = prec - 1;
 		}
 	      /* If some high bits are known to be zero,
 		 we can decrease the result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
+	      if (vr0->vrtype () == VR_RANGE
+		  && TREE_CODE (vr0->max ()) == INTEGER_CST)
 		{
-		  maxi = tree_floor_log2 (vr0->max);
+		  maxi = tree_floor_log2 (vr0->max ());
 		  /* For vr0 [0, 0] give up.  */
 		  if (maxi == -1)
 		    break;
@@ -1302,10 +1299,10 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 	     this should have been already folded and if not, it
 	     wasn't folded because of overflow.  Avoid removing the
 	     UBSAN_CHECK_* calls in that case.  */
-	  if (vr->type == VR_RANGE
-	      && (vr->min == vr->max
-		  || operand_equal_p (vr->min, vr->max, 0)))
-	    set_value_range_to_varying (vr);
+	  if (vr->vrtype () == VR_RANGE
+	      && (vr->min () == vr->max ()
+		  || operand_equal_p (vr->min (), vr->max (), 0)))
+	    set_value_range_to_varying (vr, vr->type ());
 	  return;
 	}
     }
@@ -1363,7 +1360,7 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 						  NULL);
 		      else if (TYPE_PRECISION (type) == 1
 			       && !TYPE_UNSIGNED (type))
-			set_value_range_to_varying (vr);
+			set_value_range_to_varying (vr, type);
 		      else
 			set_value_range (vr, VR_RANGE, build_int_cst (type, 0),
 					 build_int_cst (type, 1), NULL);
@@ -1381,8 +1378,7 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
 		    }
 		  else
 		    {
-		      value_range vr0 = VR_INITIALIZER;
-		      value_range vr1 = VR_INITIALIZER;
+		      value_range vr0 (type), vr1 (type);
 		      bool saved_flag_wrapv = flag_wrapv;
 		      /* Pretend the arithmetics is wrapping.  If there is
 			 any overflow, IMAGPART_EXPR will be set.  */
@@ -1406,7 +1402,7 @@  vr_values::extract_range_basic (value_range *vr, gimple *stmt)
   else if (vrp_stmt_computes_nonzero (stmt))
     set_value_range_to_nonnull (vr, type);
   else
-    set_value_range_to_varying (vr);
+    set_value_range_to_varying (vr, type);
 }
 
 
@@ -1442,9 +1438,12 @@  vr_values::extract_range_from_assignment (value_range *vr, gassign *stmt)
 	   && is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
     set_value_range_to_value (vr, gimple_assign_rhs1 (stmt), NULL);
   else
-    set_value_range_to_varying (vr);
+    {
+      tree type = TREE_TYPE (gimple_assign_lhs (stmt));
+      set_value_range_to_varying (vr, type);
+    }
 
-  if (vr->type == VR_VARYING)
+  if (vr->varying_p ())
     extract_range_basic (vr, stmt);
 }
 
@@ -1467,18 +1466,18 @@  compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 		bool *strict_overflow_p)
 {
   /* VARYING or UNDEFINED ranges cannot be compared.  */
-  if (vr0->type == VR_VARYING
-      || vr0->type == VR_UNDEFINED
-      || vr1->type == VR_VARYING
-      || vr1->type == VR_UNDEFINED)
+  if (vr0->varying_p ()
+      || vr0->undefined_p ()
+      || vr1->varying_p ()
+      || vr1->undefined_p ())
     return NULL_TREE;
 
   /* Anti-ranges need to be handled separately.  */
-  if (vr0->type == VR_ANTI_RANGE || vr1->type == VR_ANTI_RANGE)
+  if (vr0->vrtype () == VR_ANTI_RANGE || vr1->vrtype () == VR_ANTI_RANGE)
     {
       /* If both are anti-ranges, then we cannot compute any
 	 comparison.  */
-      if (vr0->type == VR_ANTI_RANGE && vr1->type == VR_ANTI_RANGE)
+      if (vr0->vrtype () == VR_ANTI_RANGE && vr1->vrtype () == VR_ANTI_RANGE)
 	return NULL_TREE;
 
       /* These comparisons are never statically computable.  */
@@ -1490,7 +1489,7 @@  compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 
       /* Equality can be computed only between a range and an
 	 anti-range.  ~[VAL1, VAL2] == [VAL1, VAL2] is always false.  */
-      if (vr0->type == VR_RANGE)
+      if (vr0->vrtype () == VR_RANGE)
 	{
 	  /* To simplify processing, make VR0 the anti-range.  */
 	  value_range *tmp = vr0;
@@ -1500,8 +1499,8 @@  compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 
       gcc_assert (comp == NE_EXPR || comp == EQ_EXPR);
 
-      if (compare_values_warnv (vr0->min, vr1->min, strict_overflow_p) == 0
-	  && compare_values_warnv (vr0->max, vr1->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr0->min (), vr1->min (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr0->max (), vr1->max (), strict_overflow_p) == 0)
 	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -1519,12 +1518,12 @@  compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
     {
       /* Equality may only be computed if both ranges represent
 	 exactly one value.  */
-      if (compare_values_warnv (vr0->min, vr0->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr1->min, vr1->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr0->min (), vr0->max (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr1->min (), vr1->max (), strict_overflow_p) == 0)
 	{
-	  int cmp_min = compare_values_warnv (vr0->min, vr1->min,
+	  int cmp_min = compare_values_warnv (vr0->min (), vr1->min (),
 					      strict_overflow_p);
-	  int cmp_max = compare_values_warnv (vr0->max, vr1->max,
+	  int cmp_max = compare_values_warnv (vr0->max (), vr1->max (),
 					      strict_overflow_p);
 	  if (cmp_min == 0 && cmp_max == 0)
 	    return boolean_true_node;
@@ -1532,9 +1531,9 @@  compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 	    return boolean_false_node;
 	}
       /* If [V0_MIN, V1_MAX] < [V1_MIN, V1_MAX] then V0 != V1.  */
-      else if (compare_values_warnv (vr0->min, vr1->max,
+      else if (compare_values_warnv (vr0->min (), vr1->max (),
 				     strict_overflow_p) == 1
-	       || compare_values_warnv (vr1->min, vr0->max,
+	       || compare_values_warnv (vr1->min (), vr0->max (),
 					strict_overflow_p) == 1)
 	return boolean_false_node;
 
@@ -1549,20 +1548,20 @@  compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
 	 make sure that both comparisons yield similar results to
 	 avoid comparing values that cannot be compared at
 	 compile-time.  */
-      cmp1 = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
-      cmp2 = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
+      cmp1 = compare_values_warnv (vr0->max (), vr1->min (), strict_overflow_p);
+      cmp2 = compare_values_warnv (vr0->min (), vr1->max (), strict_overflow_p);
       if ((cmp1 == -1 && cmp2 == -1) || (cmp1 == 1 && cmp2 == 1))
 	return boolean_true_node;
 
       /* If VR0 and VR1 represent a single value and are identical,
 	 return false.  */
-      else if (compare_values_warnv (vr0->min, vr0->max,
+      else if (compare_values_warnv (vr0->min (), vr0->max (),
 				     strict_overflow_p) == 0
-	       && compare_values_warnv (vr1->min, vr1->max,
+	       && compare_values_warnv (vr1->min (), vr1->max (),
 					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->min, vr1->min,
+	       && compare_values_warnv (vr0->min (), vr1->min (),
 					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->max, vr1->max,
+	       && compare_values_warnv (vr0->max (), vr1->max (),
 					strict_overflow_p) == 0)
 	return boolean_false_node;
 
@@ -1575,13 +1574,13 @@  compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
       int tst;
 
       /* If VR0 is to the left of VR1, return true.  */
-      tst = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
+      tst = compare_values_warnv (vr0->max (), vr1->min (), strict_overflow_p);
       if ((comp == LT_EXPR && tst == -1)
 	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
 	return boolean_true_node;
 
       /* If VR0 is to the right of VR1, return false.  */
-      tst = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
+      tst = compare_values_warnv (vr0->min (), vr1->max (), strict_overflow_p);
       if ((comp == LT_EXPR && (tst == 0 || tst == 1))
 	  || (comp == LE_EXPR && tst == 1))
 	return boolean_false_node;
@@ -1605,11 +1604,11 @@  static tree
 compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 			  bool *strict_overflow_p)
 {
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+  if (vr->varying_p () || vr->undefined_p ())
     return NULL_TREE;
 
   /* Anti-ranges need to be handled separately.  */
-  if (vr->type == VR_ANTI_RANGE)
+  if (vr->vrtype () == VR_ANTI_RANGE)
     {
       /* For anti-ranges, the only predicates that we can compute at
 	 compile time are equality and inequality.  */
@@ -1620,7 +1619,7 @@  compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
 	return NULL_TREE;
 
       /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2.  */
-      if (value_inside_range (val, vr->min, vr->max) == 1)
+      if (value_inside_range (val, vr->min (), vr->max ()) == 1)
 	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
 
       return NULL_TREE;
@@ -1630,16 +1629,16 @@  compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
     {
       /* EQ_EXPR may only be computed if VR represents exactly
 	 one value.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr->min (), vr->max (), strict_overflow_p) == 0)
 	{
-	  int cmp = compare_values_warnv (vr->min, val, strict_overflow_p);
+	  int cmp = compare_values_warnv (vr->min (), val, strict_overflow_p);
 	  if (cmp == 0)
 	    return boolean_true_node;
 	  else if (cmp == -1 || cmp == 1 || cmp == 2)
 	    return boolean_false_node;
 	}
-      else if (compare_values_warnv (val, vr->min, strict_overflow_p) == -1
-	       || compare_values_warnv (vr->max, val, strict_overflow_p) == -1)
+      else if (compare_values_warnv (val, vr->min (), strict_overflow_p) == -1
+	       || compare_values_warnv (vr->max (), val, strict_overflow_p) == -1)
 	return boolean_false_node;
 
       return NULL_TREE;
@@ -1647,14 +1646,14 @@  compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
   else if (comp == NE_EXPR)
     {
       /* If VAL is not inside VR, then they are always different.  */
-      if (compare_values_warnv (vr->max, val, strict_overflow_p) == -1
-	  || compare_values_warnv (vr->min, val, strict_overflow_p) == 1)
+      if (compare_values_warnv (vr->max (), val, strict_overflow_p) == -1
+	  || compare_values_warnv (vr->min (), val, strict_overflow_p) == 1)
 	return boolean_true_node;
 
       /* If VR represents exactly one value equal to VAL, then return
 	 false.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr->min, val, strict_overflow_p) == 0)
+      if (compare_values_warnv (vr->min (), vr->max (), strict_overflow_p) == 0
+	  && compare_values_warnv (vr->min (), val, strict_overflow_p) == 0)
 	return boolean_false_node;
 
       /* Otherwise, they may or may not be different.  */
@@ -1665,13 +1664,13 @@  compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
       int tst;
 
       /* If VR is to the left of VAL, return true.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->max (), val, strict_overflow_p);
       if ((comp == LT_EXPR && tst == -1)
 	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
 	return boolean_true_node;
 
       /* If VR is to the right of VAL, return false.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->min (), val, strict_overflow_p);
       if ((comp == LT_EXPR && (tst == 0 || tst == 1))
 	  || (comp == LE_EXPR && tst == 1))
 	return boolean_false_node;
@@ -1684,13 +1683,13 @@  compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
       int tst;
 
       /* If VR is to the right of VAL, return true.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->min (), val, strict_overflow_p);
       if ((comp == GT_EXPR && tst == 1)
 	  || (comp == GE_EXPR && (tst == 0 || tst == 1)))
 	return boolean_true_node;
 
       /* If VR is to the left of VAL, return false.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
+      tst = compare_values_warnv (vr->max (), val, strict_overflow_p);
       if ((comp == GT_EXPR && (tst == -1 || tst == 0))
 	  || (comp == GE_EXPR && tst == -1))
 	return boolean_false_node;
@@ -1714,7 +1713,7 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 
   /* TODO.  Don't adjust anti-ranges.  An anti-range may provide
      better opportunities than a regular range, but I'm not sure.  */
-  if (vr->type == VR_ANTI_RANGE)
+  if (vr->vrtype () == VR_ANTI_RANGE)
     return;
 
   chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
@@ -1722,7 +1721,7 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   /* Like in PR19590, scev can return a constant function.  */
   if (is_gimple_min_invariant (chrec))
     {
-      set_value_range_to_value (vr, chrec, vr->equiv);
+      set_value_range_to_value (vr, chrec, vr->equiv ());
       return;
     }
 
@@ -1771,7 +1770,7 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   if (TREE_CODE (step) == INTEGER_CST
       && is_gimple_val (init)
       && (TREE_CODE (init) != SSA_NAME
-	  || get_value_range (init)->type == VR_RANGE))
+	  || get_value_range (init)->vrtype () == VR_RANGE))
     {
       widest_int nit;
 
@@ -1779,7 +1778,7 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	 the number of latch executions is the correct thing to use.  */
       if (max_loop_iterations (loop, &nit))
 	{
-	  value_range maxvr = VR_INITIALIZER;
+	  value_range maxvr (TREE_TYPE (init));
 	  signop sgn = TYPE_SIGN (TREE_TYPE (step));
 	  wi::overflow_type overflow;
 
@@ -1799,9 +1798,9 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	      extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
 					      TREE_TYPE (init), init, tem);
 	      /* Likewise if the addition did.  */
-	      if (maxvr.type == VR_RANGE)
+	      if (maxvr.vrtype () == VR_RANGE)
 		{
-		  value_range initvr = VR_INITIALIZER;
+		  value_range initvr (TREE_TYPE (init));
 
 		  if (TREE_CODE (init) == SSA_NAME)
 		    initvr = *(get_value_range (init));
@@ -1815,19 +1814,19 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 		     because the loop may exit immediately.  Overflow could
 		     happen in the plus expression in this case.  */
 		  if ((dir == EV_DIR_DECREASES
-		       && compare_values (maxvr.min, initvr.min) != -1)
+		       && compare_values (maxvr.min (), initvr.min ()) != -1)
 		      || (dir == EV_DIR_GROWS
-			  && compare_values (maxvr.max, initvr.max) != 1))
+			  && compare_values (maxvr.max (), initvr.max ()) != 1))
 		    return;
 
-		  tmin = maxvr.min;
-		  tmax = maxvr.max;
+		  tmin = maxvr.min ();
+		  tmax = maxvr.max ();
 		}
 	    }
 	}
     }
 
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+  if (vr->varying_p () || vr->undefined_p ())
     {
       min = tmin;
       max = tmax;
@@ -1840,15 +1839,15 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
       else
 	min = init;
     }
-  else if (vr->type == VR_RANGE)
+  else if (vr->vrtype () == VR_RANGE)
     {
-      min = vr->min;
-      max = vr->max;
+      min = vr->min ();
+      max = vr->max ();
 
       if (dir == EV_DIR_DECREASES)
 	{
-	  /* INIT is the maximum value.  If INIT is lower than VR->MAX
-	     but no smaller than VR->MIN, set VR->MAX to INIT.  */
+	  /* INIT is the maximum value.  If INIT is lower than VR->MAX ()
+	     but no smaller than VR->MIN (), set VR->MAX () to INIT.  */
 	  if (compare_values (init, max) == -1)
 	    max = init;
 
@@ -1860,7 +1859,7 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
 	}
       else
 	{
-	  /* If INIT is bigger than VR->MIN, set VR->MIN to INIT.  */
+	  /* If INIT is bigger than VR->MIN (), set VR->MIN () to INIT.  */
 	  if (compare_values (init, min) == 1)
 	    min = init;
 
@@ -1886,7 +1885,7 @@  vr_values::adjust_range_with_scev (value_range *vr, struct loop *loop,
   if (TREE_OVERFLOW_P (max))
     max = drop_tree_overflow (max);
 
-  set_value_range (vr, VR_RANGE, min, max, vr->equiv);
+  set_value_range (vr, VR_RANGE, min, max, vr->equiv ());
 }
 
 /* Dump value ranges of all SSA_NAMEs to FILE.  */
@@ -1957,11 +1956,11 @@  vrp_valueize (tree name)
   if (TREE_CODE (name) == SSA_NAME)
     {
       value_range *vr = x_vr_values->get_value_range (name);
-      if (vr->type == VR_RANGE
-	  && (TREE_CODE (vr->min) == SSA_NAME
-	      || is_gimple_min_invariant (vr->min))
-	  && vrp_operand_equal_p (vr->min, vr->max))
-	return vr->min;
+      if (vr->vrtype () == VR_RANGE
+	  && (TREE_CODE (vr->min ()) == SSA_NAME
+	      || is_gimple_min_invariant (vr->min ()))
+	  && vrp_operand_equal_p (vr->min (), vr->max ()))
+	return vr->min ();
     }
   return name;
 }
@@ -1982,8 +1981,9 @@  vrp_valueize_1 (tree name)
 	  && prop_simulate_again_p (def_stmt))
 	return NULL_TREE;
       value_range *vr = x_vr_values->get_value_range (name);
-      if (range_int_cst_singleton_p (vr))
-	return vr->min;
+      tree singleton = vr->singleton ();
+      if (singleton)
+	return singleton;
     }
   return name;
 }
@@ -2066,12 +2066,9 @@  vr_values::get_vr_for_comparison (int i)
   /* If name N_i does not have a valid range, use N_i as its own
      range.  This allows us to compare against names that may
      have N_i in their ranges.  */
-  if (vr.type == VR_VARYING || vr.type == VR_UNDEFINED)
-    {
-      vr.type = VR_RANGE;
-      vr.min = ssa_name (i);
-      vr.max = ssa_name (i);
-    }
+  if (vr.varying_p () || vr.undefined_p ())
+    vr = value_range (VR_RANGE, vr.type (), ssa_name (i), ssa_name (i),
+		      vr.equiv ());
 
   return vr;
 }
@@ -2094,7 +2091,7 @@  vr_values::compare_name_with_value (enum tree_code comp, tree var, tree val,
   value_range equiv_vr;
 
   /* Get the set of equivalences for VAR.  */
-  e = get_value_range (var)->equiv;
+  e = get_value_range (var)->equiv ();
 
   /* Start at -1.  Set it to 0 if we do a comparison without relying
      on overflow, or 1 if all comparisons rely on overflow.  */
@@ -2180,8 +2177,8 @@  vr_values::compare_names (enum tree_code comp, tree n1, tree n2,
 
   /* Compare the ranges of every name equivalent to N1 against the
      ranges of every name equivalent to N2.  */
-  e1 = get_value_range (n1)->equiv;
-  e2 = get_value_range (n2)->equiv;
+  e1 = get_value_range (n1)->equiv ();
+  e2 = get_value_range (n2)->equiv ();
 
   /* Use the fake bitmaps if e1 or e2 are not available.  */
   if (s_obstack == NULL)
@@ -2440,10 +2437,10 @@  vr_values::vrp_evaluate_conditional (tree_code code, tree op0,
       tree type = TREE_TYPE (op0);
       value_range *vr0 = get_value_range (op0);
 
-      if (vr0->type == VR_RANGE
+      if (vr0->vrtype () == VR_RANGE
 	  && INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_min (vr0->min)
-	  && vrp_val_is_max (vr0->max)
+	  && vrp_val_is_min (vr0->min ())
+	  && vrp_val_is_max (vr0->max ())
 	  && is_gimple_min_invariant (op1))
 	{
 	  location_t location;
@@ -2572,9 +2569,9 @@  find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
   unsigned int n = gimple_switch_num_labels (stmt);
   bool take_default;
   tree case_low, case_high;
-  tree min = vr->min, max = vr->max;
+  tree min = vr->min (), max = vr->max ();
 
-  gcc_checking_assert (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE);
+  gcc_checking_assert (!vr->varying_p () && !vr->undefined_p ());
 
   take_default = !find_case_label_range (stmt, min, max, &i, &j);
 
@@ -2582,7 +2579,7 @@  find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
   *min_idx2 = 1;
   *max_idx2 = 0;
 
-  if (vr->type == VR_RANGE)
+  if (vr->vrtype () == VR_RANGE)
     {
       *min_idx1 = i;
       *max_idx1 = j;
@@ -2663,9 +2660,9 @@  vr_values::vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
       fprintf (dump_file, "\n");
     }
 
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || symbolic_range_p (vr))
+  if (vr->undefined_p ()
+      || vr->varying_p ()
+      || vr->symbolic_p ())
     return;
 
   /* Find the single edge that is taken from the switch expression.  */
@@ -2809,29 +2806,20 @@  vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 		 See PR53465 and PR54767.  */
 	      if (e->flags & EDGE_DFS_BACK)
 		{
-		  if (vr_arg.type == VR_RANGE
-		      || vr_arg.type == VR_ANTI_RANGE)
+		  if (!vr_arg.varying_p ()
+		      && !vr_arg.undefined_p ())
 		    {
-		      vr_arg.equiv = NULL;
-		      if (symbolic_range_p (&vr_arg))
-			{
-			  vr_arg.type = VR_VARYING;
-			  vr_arg.min = NULL_TREE;
-			  vr_arg.max = NULL_TREE;
-			}
+		      vr_arg.equiv_clear ();
+		      if (vr_arg.symbolic_p ())
+			vr_arg.set_varying ();
 		    }
 		}
 	      else
 		{
 		  /* If the non-backedge arguments range is VR_VARYING then
 		     we can still try recording a simple equivalence.  */
-		  if (vr_arg.type == VR_VARYING)
-		    {
-		      vr_arg.type = VR_RANGE;
-		      vr_arg.min = arg;
-		      vr_arg.max = arg;
-		      vr_arg.equiv = NULL;
-		    }
+		  if (vr_arg.varying_p ())
+		    vr_arg.equiv_clear ();
 		}
 	    }
 	  else
@@ -2839,10 +2827,7 @@  vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 	      if (TREE_OVERFLOW_P (arg))
 		arg = drop_tree_overflow (arg);
 
-	      vr_arg.type = VR_RANGE;
-	      vr_arg.min = arg;
-	      vr_arg.max = arg;
-	      vr_arg.equiv = NULL;
+	      vr_arg = value_range (VR_RANGE, TREE_TYPE (arg), arg, arg);
 	    }
 
 	  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2857,17 +2842,17 @@  vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 	  if (first)
 	    copy_value_range (vr_result, &vr_arg);
 	  else
-	    vrp_meet (vr_result, &vr_arg);
+	    vr_result->union_ (&vr_arg);
 	  first = false;
 
-	  if (vr_result->type == VR_VARYING)
+	  if (vr_result->varying_p ())
 	    break;
 	}
     }
 
-  if (vr_result->type == VR_VARYING)
+  if (vr_result->varying_p ())
     goto varying;
-  else if (vr_result->type == VR_UNDEFINED)
+  else if (vr_result->undefined_p ())
     goto update_range;
 
   old_edges = vr_phi_edge_counts[SSA_NAME_VERSION (lhs)];
@@ -2883,21 +2868,21 @@  vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
   if (edges > 0
       && gimple_phi_num_args (phi) > 1
       && edges == old_edges
-      && lhs_vr->type != VR_UNDEFINED
+      && !lhs_vr->undefined_p ()
       && may_simulate_backedge_again)
     {
       /* Compare old and new ranges, fall back to varying if the
          values are not comparable.  */
-      int cmp_min = compare_values (lhs_vr->min, vr_result->min);
+      int cmp_min = compare_values (lhs_vr->min (), vr_result->min ());
       if (cmp_min == -2)
 	goto varying;
-      int cmp_max = compare_values (lhs_vr->max, vr_result->max);
+      int cmp_max = compare_values (lhs_vr->max (), vr_result->max ());
       if (cmp_max == -2)
 	goto varying;
 
       /* For non VR_RANGE or for pointers fall back to varying if
 	 the range changed.  */
-      if ((lhs_vr->type != VR_RANGE || vr_result->type != VR_RANGE
+      if ((lhs_vr->vrtype () != VR_RANGE || vr_result->vrtype () != VR_RANGE
 	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
 	  && (cmp_min != 0 || cmp_max != 0))
 	goto varying;
@@ -2910,24 +2895,27 @@  vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
 	 times to reach -INF.  Going to -INF + 1 also lets the following
 	 iteration compute whether there will be any overflow, at the
 	 expense of one additional iteration.  */
+      tree new_min = vr_result->min ();
+      tree new_max = vr_result->max ();
       if (cmp_min < 0)
-	vr_result->min = lhs_vr->min;
+	new_min = lhs_vr->min ();
       else if (cmp_min > 0
-	       && !vrp_val_is_min (vr_result->min))
-	vr_result->min
-	  = int_const_binop (PLUS_EXPR,
-			     vrp_val_min (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
+	       && !vrp_val_is_min (vr_result->min ()))
+	new_min = int_const_binop (PLUS_EXPR,
+				   vrp_val_min (vr_result->type ()),
+				   build_int_cst (vr_result->type (), 1));
 
       /* Similarly for the maximum value.  */
       if (cmp_max > 0)
-	vr_result->max = lhs_vr->max;
+	new_max = lhs_vr->max ();
       else if (cmp_max < 0
-	       && !vrp_val_is_max (vr_result->max))
-	vr_result->max
-	  = int_const_binop (MINUS_EXPR,
-			     vrp_val_max (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
+	       && !vrp_val_is_max (vr_result->max ()))
+	new_max = int_const_binop (MINUS_EXPR,
+				   vrp_val_max (vr_result->type ()),
+				   build_int_cst (vr_result->type (), 1));
+
+      *vr_result = value_range (vr_result->vrtype (), vr_result->type (),
+				new_min, new_max, vr_result->equiv ());
 
       /* If we dropped either bound to +-INF then if this is a loop
 	 PHI node SCEV may known more about its value-range.  */
@@ -2941,7 +2929,7 @@  vr_values::extract_range_from_phi_node (gphi *phi, value_range *vr_result)
   goto update_range;
 
 varying:
-  set_value_range_to_varying (vr_result);
+  set_value_range_to_varying (vr_result, TREE_TYPE (lhs));
 
 scev_check:
   /* If this is a loop PHI node SCEV may known more about its value-range.
@@ -2957,12 +2945,12 @@  infinite_check:
   /* If we will end up with a (-INF, +INF) range, set it to
      VARYING.  Same if the previous max value was invalid for
      the type and we end up with vr_result.min > vr_result.max.  */
-  if ((vr_result->type == VR_RANGE || vr_result->type == VR_ANTI_RANGE)
-      && !((vrp_val_is_max (vr_result->max) && vrp_val_is_min (vr_result->min))
-	   || compare_values (vr_result->min, vr_result->max) > 0))
+  if ((!vr_result->varying_p () && !vr_result->undefined_p ())
+      && !((vrp_val_is_max (vr_result->max ()) && vrp_val_is_min (vr_result->min ()))
+	   || compare_values (vr_result->min (), vr_result->max ()) > 0))
     ;
   else
-    set_value_range_to_varying (vr_result);
+    set_value_range_to_varying (vr_result, TREE_TYPE (lhs));
 
   /* If the new range is different than the previous value, keep
      iterating.  */
@@ -3071,8 +3059,8 @@  vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
       vr = get_value_range (op0);
       if (range_int_cst_p (vr))
 	{
-	  op0min = vr->min;
-	  op0max = vr->max;
+	  op0min = vr->min ();
+	  op0max = vr->max ();
 	}
     }
 
@@ -3081,7 +3069,7 @@  vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi,
     {
       value_range *vr1 = get_value_range (op1);
       if (range_int_cst_p (vr1))
-	op1min = vr1->min;
+	op1min = vr1->min ();
     }
   if (rhs_code == TRUNC_MOD_EXPR
       && TREE_CODE (op1min) == INTEGER_CST
@@ -3285,8 +3273,8 @@  vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
   tree op0 = gimple_assign_rhs1 (stmt);
   tree op1 = gimple_assign_rhs2 (stmt);
   tree op = NULL_TREE;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
+  value_range vr0 (TREE_TYPE (op0));
+  value_range vr1 (TREE_TYPE (op1));
   wide_int may_be_nonzero0, may_be_nonzero1;
   wide_int must_be_nonzero0, must_be_nonzero1;
   wide_int mask;
@@ -3405,10 +3393,10 @@  test_for_singularity (enum tree_code cond_code, tree op0,
      value range information we have for op0.  */
   if (min && max)
     {
-      if (compare_values (vr->min, min) == 1)
-	min = vr->min;
-      if (compare_values (vr->max, max) == -1)
-	max = vr->max;
+      if (compare_values (vr->min (), min) == 1)
+	min = vr->min ();
+      if (compare_values (vr->max (), max) == -1)
+	max = vr->max ();
 
       /* If the new min/max values have converged to a single value,
 	 then there is only one value which can satisfy the condition,
@@ -3431,14 +3419,14 @@  range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
   signop src_sgn;
 
   /* We can only handle integral and pointer types.  */
-  src_type = TREE_TYPE (vr->min);
+  src_type = vr->type ();
   if (!INTEGRAL_TYPE_P (src_type)
       && !POINTER_TYPE_P (src_type))
     return false;
 
   /* An extension is fine unless VR is SIGNED and dest_sgn is UNSIGNED,
      and so is an identity transform.  */
-  src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
+  src_precision = TYPE_PRECISION (vr->type ());
   src_sgn = TYPE_SIGN (src_type);
   if ((src_precision < dest_precision
        && !(dest_sgn == UNSIGNED && src_sgn == SIGNED))
@@ -3446,9 +3434,7 @@  range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
     return true;
 
   /* Now we can only handle ranges with constant bounds.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (!range_int_cst_p (vr))
     return false;
 
   /* For sign changes, the MSB of the wide_int has to be clear.
@@ -3456,17 +3442,17 @@  range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
      a signed wide_int, while a negative value cannot be represented
      by an unsigned wide_int.  */
   if (src_sgn != dest_sgn
-      && (wi::lts_p (wi::to_wide (vr->min), 0)
-	  || wi::lts_p (wi::to_wide (vr->max), 0)))
+      && (wi::lts_p (wi::to_wide (vr->min ()), 0)
+	  || wi::lts_p (wi::to_wide (vr->max ()), 0)))
     return false;
 
   /* Then we can perform the conversion on both ends and compare
      the result for equality.  */
-  tem = wi::ext (wi::to_widest (vr->min), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->min))
+  tem = wi::ext (wi::to_widest (vr->min ()), dest_precision, dest_sgn);
+  if (tem != wi::to_widest (vr->min ()))
     return false;
-  tem = wi::ext (wi::to_widest (vr->max), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->max))
+  tem = wi::ext (wi::to_widest (vr->max ()), dest_precision, dest_sgn);
+  if (tem != wi::to_widest (vr->max ()))
     return false;
 
   return true;
@@ -3493,7 +3479,7 @@  vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
 
       /* If we have range information for OP0, then we might be
 	 able to simplify this conditional. */
-      if (vr->type == VR_RANGE)
+      if (vr->vrtype () == VR_RANGE)
 	{
 	  tree new_tree = test_for_singularity (cond_code, op0, op1, vr);
 	  if (new_tree)
@@ -3636,9 +3622,9 @@  vr_values::simplify_switch_using_ranges (gswitch *stmt)
       vr = get_value_range (op);
 
       /* We can only handle integer ranges.  */
-      if ((vr->type != VR_RANGE
-	   && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->varying_p ()
+	  || vr->undefined_p ()
+	  || vr->symbolic_p ())
 	return false;
 
       /* Find case label for min/max of the value range.  */
@@ -3666,7 +3652,7 @@  vr_values::simplify_switch_using_ranges (gswitch *stmt)
      value range.  */
   size_t min_idx = 1, max_idx = 0;
   if (vr != NULL)
-    find_case_label_range (stmt, vr->min, vr->max, &min_idx, &max_idx);
+    find_case_label_range (stmt, vr->min (), vr->max (), &min_idx, &max_idx);
   if (min_idx <= max_idx)
     {
       tree min_label = gimple_switch_label (stmt, min_idx);
@@ -3674,10 +3660,10 @@  vr_values::simplify_switch_using_ranges (gswitch *stmt)
 
       /* Avoid changing the type of the case labels when truncating.  */
       tree case_label_type = TREE_TYPE (CASE_LOW (min_label));
-      tree vr_min = fold_convert (case_label_type, vr->min);
-      tree vr_max = fold_convert (case_label_type, vr->max);
+      tree vr_min = fold_convert (case_label_type, vr->min ());
+      tree vr_max = fold_convert (case_label_type, vr->max ());
 
-      if (vr->type == VR_RANGE)
+      if (vr->vrtype () == VR_RANGE)
 	{
 	  /* If OP's value range is [2,8] and the low label range is
 	     0 ... 3, truncate the label's range to 2 .. 3.  */
@@ -3693,7 +3679,7 @@  vr_values::simplify_switch_using_ranges (gswitch *stmt)
 	      && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0)
 	    CASE_HIGH (max_label) = vr_max;
 	}
-      else if (vr->type == VR_ANTI_RANGE)
+      else if (vr->vrtype () == VR_ANTI_RANGE)
 	{
 	  tree one_cst = build_one_cst (case_label_type);
 
@@ -3930,9 +3916,7 @@  vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
   gassign *conv;
 
   /* We can only handle constant ranges.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (!range_int_cst_p (vr))
     return false;
 
   /* First check if we can use a signed type in place of an unsigned.  */
@@ -4088,26 +4072,26 @@  bool
 vr_values::two_valued_val_range_p (tree var, tree *a, tree *b)
 {
   value_range *vr = get_value_range (var);
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
+  if (vr->varying_p ()
+      || vr->undefined_p ()
+      || TREE_CODE (vr->min ()) != INTEGER_CST
+      || TREE_CODE (vr->max ()) != INTEGER_CST)
     return false;
 
-  if (vr->type == VR_RANGE
-      && wi::to_wide (vr->max) - wi::to_wide (vr->min) == 1)
+  if (vr->vrtype () == VR_RANGE
+      && wi::to_wide (vr->max ()) - wi::to_wide (vr->min ()) == 1)
     {
-      *a = vr->min;
-      *b = vr->max;
+      *a = vr->min ();
+      *b = vr->max ();
       return true;
     }
 
   /* ~[TYPE_MIN + 1, TYPE_MAX - 1] */
-  if (vr->type == VR_ANTI_RANGE
-      && (wi::to_wide (vr->min)
+  if (vr->vrtype () == VR_ANTI_RANGE
+      && (wi::to_wide (vr->min ())
 	  - wi::to_wide (vrp_val_min (TREE_TYPE (var)))) == 1
       && (wi::to_wide (vrp_val_max (TREE_TYPE (var)))
-	  - wi::to_wide (vr->max)) == 1)
+	  - wi::to_wide (vr->max ())) == 1)
     {
       *a = vrp_val_min (TREE_TYPE (var));
       *b = vrp_val_max (TREE_TYPE (var));
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 487a800c1ea..496707856c3 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -72,7 +72,7 @@  class vr_values
   void cleanup_edges_and_switches (void);
 
  private:
-  void add_equivalence (bitmap *, const_tree);
+  bitmap add_equivalence (bitmap, const_tree);
   bool vrp_stmt_computes_nonzero (gimple *);
   bool op_with_boolean_value_range_p (tree);
   bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *);
@@ -142,7 +142,5 @@  class vr_values
   vec<switch_update> to_update_switch_stmts;
 };
 
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
-
 extern tree get_output_for_vrp (gimple *);
 #endif /* GCC_VR_VALUES_H */