diff mbox series

move value_range_equiv class to own file

Message ID 85cc98b5-13ad-6fda-a735-209e517450a3@redhat.com
State New
Headers show
Series move value_range_equiv class to own file | expand

Commit Message

Aldy Hernandez May 18, 2020, 6:08 p.m. UTC
We already moved the value_range class into its own class in the last 
release.  I think it's time to move the value_range_equiv stuff into its 
own class, as it's a distraction from the VRP code.

I've moved it to value-range-equiv.*, and gave it a semblance of order, 
by putting the constructors and setters at the beginning, the dumpers at 
the bottom, etc.

No functional changes.

OK for mainline?
Aldy

Comments

Richard Biener May 19, 2020, 7:09 a.m. UTC | #1
On Mon, May 18, 2020 at 8:13 PM Aldy Hernandez via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> We already moved the value_range class into its own class in the last
> release.  I think it's time to move the value_range_equiv stuff into its
> own class, as it's a distraction from the VRP code.
>
> I've moved it to value-range-equiv.*, and gave it a semblance of order,
> by putting the constructors and setters at the beginning, the dumpers at
> the bottom, etc.
>
> No functional changes.
>
> OK for mainline?

Just a note - I dislike spreading all the VRP code across so many files.
It gets harder and harder to find pieces that once were just in the single
tree-vrp.c file ...

But I'm staying out of here as promised.

It would be much more useful if, for example, the -Warray-bound
warning were split out from the "old" VRP code and put somewhere
else (preferably not another walk over the IL but combined with a
diagnostic pass already performing a EVRP dom walk).

Likewise for the jump-threading bits.

Richard.

> Aldy
Li, Pan2 via Gcc-patches May 19, 2020, 8:46 p.m. UTC | #2
On Tue, 2020-05-19 at 09:09 +0200, Richard Biener wrote:
> On Mon, May 18, 2020 at 8:13 PM Aldy Hernandez via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> > We already moved the value_range class into its own class in the last
> > release.  I think it's time to move the value_range_equiv stuff into its
> > own class, as it's a distraction from the VRP code.
> > 
> > I've moved it to value-range-equiv.*, and gave it a semblance of order,
> > by putting the constructors and setters at the beginning, the dumpers at
> > the bottom, etc.
> > 
> > No functional changes.
> > 
> > OK for mainline?
> 
> Just a note - I dislike spreading all the VRP code across so many files.
> It gets harder and harder to find pieces that once were just in the single
> tree-vrp.c file ...
> 
> But I'm staying out of here as promised.
> 
> It would be much more useful if, for example, the -Warray-bound
> warning were split out from the "old" VRP code and put somewhere
> else (preferably not another walk over the IL but combined with a
> diagnostic pass already performing a EVRP dom walk).
We've been looking at doing it as part of the path isolation code so that we can
(conditionally) turn the out of range references into traps.


> 
> Likewise for the jump-threading bits.
VRP jump threading should just go away.  BUt that's blocked on getting the Ranger
bits in which is what all this is leading up to.

jeff
Li, Pan2 via Gcc-patches May 31, 2020, 5:31 p.m. UTC | #3
On Mon, 2020-05-18 at 20:08 +0200, Aldy Hernandez wrote:
> We already moved the value_range class into its own class in the last 
> release.  I think it's time to move the value_range_equiv stuff into its 
> own class, as it's a distraction from the VRP code.
> 
> I've moved it to value-range-equiv.*, and gave it a semblance of order, 
> by putting the constructors and setters at the beginning, the dumpers at 
> the bottom, etc.
> 
> No functional changes.
> 
> OK for mainline?
OK.

Jeff
diff mbox series

Patch

commit 10bcfd4659a32b1ef31eaa48f866311d53445de6
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Sun May 17 14:55:51 2020 +0200

    Move value_range_equiv code to its own file.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 9ba21f735f6..711d1fe308e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1641,6 +1641,7 @@  OBJS = \
 	unique-ptr-tests.o \
 	valtrack.o \
 	value-range.o \
+	value-range-equiv.o \
 	value-prof.o \
 	var-tracking.o \
 	varasm.o \
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 4b5df543c00..953ca508fa2 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -67,6 +67,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "vr-values.h"
 #include "builtins.h"
 #include "range-op.h"
+#include "value-range-equiv.h"
 
 /* Set of SSA names found live during the RPO traversal of the function
    for still active basic-blocks.  */
@@ -309,210 +310,6 @@  private:
 							const void *);
 };
 
-void
-value_range_equiv::set_equiv (bitmap equiv)
-{
-  if (undefined_p () || varying_p ())
-    equiv = NULL;
-  /* 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);
-    }
-}
-
-/* Initialize value_range.  */
-
-void
-value_range_equiv::set (tree min, tree max, bitmap equiv,
-			value_range_kind kind)
-{
-  value_range::set (min, max, kind);
-  set_equiv (equiv);
-  if (flag_checking)
-    check ();
-}
-
-value_range_equiv::value_range_equiv (tree min, tree max, bitmap equiv,
-				      value_range_kind kind)
-{
-  m_equiv = NULL;
-  set (min, max, equiv, kind);
-}
-
-value_range_equiv::value_range_equiv (const value_range &other)
-{
-  m_equiv = NULL;
-  set (other.min(), other.max (), NULL, other.kind ());
-}
-
-/* Like set, but keep the equivalences in place.  */
-
-void
-value_range_equiv::update (tree min, tree max, value_range_kind kind)
-{
-  set (min, max,
-       (kind != VR_UNDEFINED && kind != VR_VARYING) ? m_equiv : NULL, kind);
-}
-
-/* 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_equiv::deep_copy (const value_range_equiv *from)
-{
-  set (from->min (), from->max (), from->m_equiv, from->m_kind);
-}
-
-void
-value_range_equiv::move (value_range_equiv *from)
-{
-  set (from->min (), from->max (), NULL, from->m_kind);
-  m_equiv = from->m_equiv;
-  from->m_equiv = NULL;
-}
-
-void
-value_range_equiv::check ()
-{
-  value_range::check ();
-  switch (m_kind)
-    {
-    case VR_UNDEFINED:
-    case VR_VARYING:
-      gcc_assert (!m_equiv || bitmap_empty_p (m_equiv));
-    default:;
-    }
-}
-
-/* Return true if the bitmaps B1 and B2 are equal.  */
-
-static bool
-vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
-{
-  return (b1 == b2
-	  || ((!b1 || bitmap_empty_p (b1))
-	      && (!b2 || bitmap_empty_p (b2)))
-	  || (b1 && b2
-	      && bitmap_equal_p (b1, b2)));
-}
-
-/* Returns TRUE if THIS == OTHER.  Ignores the equivalence bitmap if
-   IGNORE_EQUIVS is TRUE.  */
-
-bool
-value_range_equiv::equal_p (const value_range_equiv &other,
-			    bool ignore_equivs) const
-{
-  return (value_range::equal_p (other)
-	  && (ignore_equivs
-	      || vrp_bitmap_equal_p (m_equiv, other.m_equiv)));
-}
-
-void
-value_range_equiv::set_undefined ()
-{
-  set (NULL, NULL, NULL, VR_UNDEFINED);
-}
-
-void
-value_range_equiv::set_varying (tree type)
-{
-  value_range::set_varying (type);
-  equiv_clear ();
-}
-
-void
-value_range_equiv::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::equiv_add (const_tree var,
-			      const value_range_equiv *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);
-}
-
-void
-value_range_equiv::dump (FILE *file) const
-{
-  value_range::dump (file);
-  if ((m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
-      && 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);
-    }
-}
-
-void
-value_range_equiv::dump () const
-{
-  dump (stderr);
-}
-
-void
-dump_value_range (FILE *file, const value_range_equiv *vr)
-{
-  if (!vr)
-    fprintf (file, "[]");
-  else
-    vr->dump (file);
-}
-
-DEBUG_FUNCTION void
-debug (const value_range_equiv *vr)
-{
-  dump_value_range (stderr, vr);
-}
-
-DEBUG_FUNCTION void
-debug (const value_range_equiv &vr)
-{
-  dump_value_range (stderr, &vr);
-}
-
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 bool
@@ -594,15 +391,6 @@  intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
   return vr_type;
 }
 
-void
-value_range_equiv::set (tree val)
-{
-  gcc_assert (TREE_CODE (val) == SSA_NAME || is_gimple_min_invariant (val));
-  if (TREE_OVERFLOW_P (val))
-    val = drop_tree_overflow (val);
-  set (val, val);
-}
-
 /* Return true if max and min of VR are INTEGER_CST.  It's not necessary
    a singleton.  */
 
@@ -4811,92 +4599,6 @@  vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
   return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING;
 }
 
-void
-value_range_equiv::intersect (const value_range_equiv *other)
-{
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "Intersecting\n  ");
-      dump_value_range (dump_file, this);
-      fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, other);
-      fprintf (dump_file, "\n");
-    }
-
-  /* If THIS is varying we want to pick up equivalences from OTHER.
-     Just special-case this here rather than trying to fixup after the
-     fact.  */
-  if (this->varying_p ())
-    this->deep_copy (other);
-  else
-    {
-      value_range tem = intersect_helper (this, other);
-      this->update (tem.min (), tem.max (), tem.kind ());
-
-      /* If the result is VR_UNDEFINED there is no need to mess with
-	 equivalencies.  */
-      if (!undefined_p ())
-	{
-	  /* The resulting set of equivalences for range intersection
-	     is the union of the two sets.  */
-	  if (m_equiv && other->m_equiv && m_equiv != other->m_equiv)
-	    bitmap_ior_into (m_equiv, other->m_equiv);
-	  else if (other->m_equiv && !m_equiv)
-	    {
-	      /* All equivalence bitmaps are allocated from the same
-		 obstack.  So we can use the obstack associated with
-		 VR to allocate this->m_equiv.  */
-	      m_equiv = BITMAP_ALLOC (other->m_equiv->obstack);
-	      bitmap_copy (m_equiv, other->m_equiv);
-	    }
-	}
-    }
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, this);
-      fprintf (dump_file, "\n");
-    }
-}
-
-void
-value_range_equiv::union_ (const value_range_equiv *other)
-{
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "Meeting\n  ");
-      dump_value_range (dump_file, this);
-      fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, other);
-      fprintf (dump_file, "\n");
-    }
-
-  /* If THIS is undefined we want to pick up equivalences from OTHER.
-     Just special-case this here rather than trying to fixup after the fact.  */
-  if (this->undefined_p ())
-    this->deep_copy (other);
-  else
-    {
-      value_range tem = union_helper (this, other);
-      this->update (tem.min (), tem.max (), tem.kind ());
-
-      /* The resulting set of equivalences is always the intersection of
-	 the two sets.  */
-      if (this->m_equiv && other->m_equiv && this->m_equiv != other->m_equiv)
-	bitmap_and_into (this->m_equiv, other->m_equiv);
-      else if (this->m_equiv && !other->m_equiv)
-	bitmap_clear (this->m_equiv);
-    }
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "to\n  ");
-      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.  */
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index aa8201f7359..b3d187ffdf1 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -22,76 +22,6 @@  along with GCC; see the file COPYING3.  If not see
 
 #include "value-range.h"
 
-/* Note value_range_equiv cannot currently be used with GC memory,
-   only value_range is fully set up for this.  */
-class GTY((user)) value_range_equiv : public value_range
-{
- public:
-  value_range_equiv ();
-  value_range_equiv (const value_range &);
-  /* Deep-copies equiv bitmap argument.  */
-  value_range_equiv (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
-
-  /* Shallow-copies equiv bitmap.  */
-  value_range_equiv (const value_range_equiv &) /* = delete */;
-  /* Shallow-copies equiv bitmap.  */
-  value_range_equiv& operator=(const value_range_equiv &) /* = delete */;
-
-  /* Move equiv bitmap from source range.  */
-  void move (value_range_equiv *);
-
-  /* Leaves equiv bitmap alone.  */
-  void update (tree, tree, value_range_kind = VR_RANGE);
-  /* Deep-copies equiv bitmap argument.  */
-  void set (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
-  void set (tree);
-
-  bool operator== (const value_range_equiv &) const /* = delete */;
-  bool operator!= (const value_range_equiv &) const /* = delete */;
-  void intersect (const value_range_equiv *);
-  void union_ (const value_range_equiv *);
-  bool equal_p (const value_range_equiv &, bool ignore_equivs) const;
-
-  /* Types of value ranges.  */
-  void set_undefined ();
-  void set_varying (tree);
-
-  /* Equivalence bitmap methods.  */
-  bitmap equiv () const;
-  void equiv_clear ();
-  void equiv_add (const_tree, const value_range_equiv *,
-		  bitmap_obstack * = NULL);
-
-  /* Misc methods.  */
-  void deep_copy (const value_range_equiv *);
-  void dump (FILE *) const;
-  void dump () const;
-
- private:
-  /* Deep-copies bitmap argument.  */
-  void set_equiv (bitmap);
-  void check ();
-
-  /* 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;
-};
-
-inline
-value_range_equiv::value_range_equiv ()
-  : value_range ()
-{
-  m_equiv = NULL;
-}
-
-inline bitmap
-value_range_equiv::equiv () const
-{
-  return m_equiv;
-}
-
-extern void dump_value_range (FILE *, const value_range_equiv *);
-
 struct assert_info
 {
   /* Predicate code for the ASSERT_EXPR.  Must be COMPARISON_CLASS_P.  */
diff --git a/gcc/value-range-equiv.cc b/gcc/value-range-equiv.cc
new file mode 100644
index 00000000000..24132e3546e
--- /dev/null
+++ b/gcc/value-range-equiv.cc
@@ -0,0 +1,322 @@ 
+/* Support routines for value ranges with equivalences.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+#include "tree-pretty-print.h"
+#include "value-range-equiv.h"
+
+value_range_equiv::value_range_equiv (tree min, tree max, bitmap equiv,
+				      value_range_kind kind)
+{
+  m_equiv = NULL;
+  set (min, max, equiv, kind);
+}
+
+value_range_equiv::value_range_equiv (const value_range &other)
+{
+  m_equiv = NULL;
+  set (other.min(), other.max (), NULL, other.kind ());
+}
+
+void
+value_range_equiv::set (tree min, tree max, bitmap equiv,
+			value_range_kind kind)
+{
+  value_range::set (min, max, kind);
+  set_equiv (equiv);
+  if (flag_checking)
+    check ();
+}
+
+void
+value_range_equiv::set (tree val)
+{
+  gcc_assert (TREE_CODE (val) == SSA_NAME || is_gimple_min_invariant (val));
+  if (TREE_OVERFLOW_P (val))
+    val = drop_tree_overflow (val);
+  set (val, val);
+}
+
+void
+value_range_equiv::set_undefined ()
+{
+  set (NULL, NULL, NULL, VR_UNDEFINED);
+}
+
+void
+value_range_equiv::set_varying (tree type)
+{
+  value_range::set_varying (type);
+  equiv_clear ();
+}
+
+/* Like set, but keep the equivalences in place.  */
+
+void
+value_range_equiv::update (tree min, tree max, value_range_kind kind)
+{
+  set (min, max,
+       (kind != VR_UNDEFINED && kind != VR_VARYING) ? m_equiv : NULL, kind);
+}
+
+/* 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_equiv::deep_copy (const value_range_equiv *from)
+{
+  set (from->min (), from->max (), from->m_equiv, from->m_kind);
+}
+
+void
+value_range_equiv::move (value_range_equiv *from)
+{
+  set (from->min (), from->max (), NULL, from->m_kind);
+  m_equiv = from->m_equiv;
+  from->m_equiv = NULL;
+}
+
+void
+value_range_equiv::set_equiv (bitmap equiv)
+{
+  if (undefined_p () || varying_p ())
+    equiv = NULL;
+  /* 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);
+    }
+}
+
+void
+value_range_equiv::check ()
+{
+  value_range::check ();
+  switch (m_kind)
+    {
+    case VR_UNDEFINED:
+    case VR_VARYING:
+      gcc_assert (!m_equiv || bitmap_empty_p (m_equiv));
+    default:;
+    }
+}
+
+/* Return true if the bitmaps B1 and B2 are equal.  */
+
+static bool
+vr_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
+{
+  return (b1 == b2
+	  || ((!b1 || bitmap_empty_p (b1))
+	      && (!b2 || bitmap_empty_p (b2)))
+	  || (b1 && b2
+	      && bitmap_equal_p (b1, b2)));
+}
+
+/* Returns TRUE if THIS == OTHER.  Ignores the equivalence bitmap if
+   IGNORE_EQUIVS is TRUE.  */
+
+bool
+value_range_equiv::equal_p (const value_range_equiv &other,
+			    bool ignore_equivs) const
+{
+  return (value_range::equal_p (other)
+	  && (ignore_equivs || vr_bitmap_equal_p (m_equiv, other.m_equiv)));
+}
+
+void
+value_range_equiv::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::equiv_add (const_tree var,
+			      const value_range_equiv *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);
+}
+
+void
+value_range_equiv::intersect (const value_range_equiv *other)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Intersecting\n  ");
+      dump_value_range (dump_file, this);
+      fprintf (dump_file, "\nand\n  ");
+      dump_value_range (dump_file, other);
+      fprintf (dump_file, "\n");
+    }
+
+  /* If THIS is varying we want to pick up equivalences from OTHER.
+     Just special-case this here rather than trying to fixup after the
+     fact.  */
+  if (this->varying_p ())
+    this->deep_copy (other);
+  else
+    {
+      value_range tem = intersect_helper (this, other);
+      this->update (tem.min (), tem.max (), tem.kind ());
+
+      /* If the result is VR_UNDEFINED there is no need to mess with
+	 equivalencies.  */
+      if (!undefined_p ())
+	{
+	  /* The resulting set of equivalences for range intersection
+	     is the union of the two sets.  */
+	  if (m_equiv && other->m_equiv && m_equiv != other->m_equiv)
+	    bitmap_ior_into (m_equiv, other->m_equiv);
+	  else if (other->m_equiv && !m_equiv)
+	    {
+	      /* All equivalence bitmaps are allocated from the same
+		 obstack.  So we can use the obstack associated with
+		 VR to allocate this->m_equiv.  */
+	      m_equiv = BITMAP_ALLOC (other->m_equiv->obstack);
+	      bitmap_copy (m_equiv, other->m_equiv);
+	    }
+	}
+    }
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "to\n  ");
+      dump_value_range (dump_file, this);
+      fprintf (dump_file, "\n");
+    }
+}
+
+void
+value_range_equiv::union_ (const value_range_equiv *other)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Meeting\n  ");
+      dump_value_range (dump_file, this);
+      fprintf (dump_file, "\nand\n  ");
+      dump_value_range (dump_file, other);
+      fprintf (dump_file, "\n");
+    }
+
+  /* If THIS is undefined we want to pick up equivalences from OTHER.
+     Just special-case this here rather than trying to fixup after the fact.  */
+  if (this->undefined_p ())
+    this->deep_copy (other);
+  else
+    {
+      value_range tem = union_helper (this, other);
+      this->update (tem.min (), tem.max (), tem.kind ());
+
+      /* The resulting set of equivalences is always the intersection of
+	 the two sets.  */
+      if (this->m_equiv && other->m_equiv && this->m_equiv != other->m_equiv)
+	bitmap_and_into (this->m_equiv, other->m_equiv);
+      else if (this->m_equiv && !other->m_equiv)
+	bitmap_clear (this->m_equiv);
+    }
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "to\n  ");
+      dump_value_range (dump_file, this);
+      fprintf (dump_file, "\n");
+    }
+}
+
+void
+value_range_equiv::dump (FILE *file) const
+{
+  value_range::dump (file);
+  if ((m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
+      && 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);
+    }
+}
+
+void
+value_range_equiv::dump () const
+{
+  dump (stderr);
+}
+
+void
+dump_value_range (FILE *file, const value_range_equiv *vr)
+{
+  if (!vr)
+    fprintf (file, "[]");
+  else
+    vr->dump (file);
+}
+
+DEBUG_FUNCTION void
+debug (const value_range_equiv *vr)
+{
+  dump_value_range (stderr, vr);
+}
+
+DEBUG_FUNCTION void
+debug (const value_range_equiv &vr)
+{
+  dump_value_range (stderr, &vr);
+}
diff --git a/gcc/value-range-equiv.h b/gcc/value-range-equiv.h
new file mode 100644
index 00000000000..274221226e6
--- /dev/null
+++ b/gcc/value-range-equiv.h
@@ -0,0 +1,82 @@ 
+/* Support routines for value ranges with equivalences.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_VALUE_RANGE_EQUIV_H
+#define GCC_VALUE_RANGE_EQUIV_H
+
+#include "value-range.h"
+
+/* Note value_range_equiv cannot currently be used with GC memory,
+   only value_range is fully set up for this.  */
+class GTY((user)) value_range_equiv : public value_range
+{
+ public:
+  value_range_equiv () : value_range () { m_equiv = NULL; }
+  value_range_equiv (const value_range &);
+  /* Deep-copies equiv bitmap argument.  */
+  value_range_equiv (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
+
+  /* Shallow-copies equiv bitmap.  */
+  value_range_equiv (const value_range_equiv &) /* = delete */;
+  /* Shallow-copies equiv bitmap.  */
+  value_range_equiv& operator=(const value_range_equiv &) /* = delete */;
+
+  /* Move equiv bitmap from source range.  */
+  void move (value_range_equiv *);
+
+  /* Leaves equiv bitmap alone.  */
+  void update (tree, tree, value_range_kind = VR_RANGE);
+  /* Deep-copies equiv bitmap argument.  */
+  void set (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
+  void set (tree);
+
+  bool operator== (const value_range_equiv &) const /* = delete */;
+  bool operator!= (const value_range_equiv &) const /* = delete */;
+  void intersect (const value_range_equiv *);
+  void union_ (const value_range_equiv *);
+  bool equal_p (const value_range_equiv &, bool ignore_equivs) const;
+
+  /* Types of value ranges.  */
+  void set_undefined ();
+  void set_varying (tree);
+
+  /* Equivalence bitmap methods.  */
+  bitmap equiv () const { return m_equiv; }
+  void equiv_clear ();
+  void equiv_add (const_tree, const value_range_equiv *,
+		  bitmap_obstack * = NULL);
+
+  /* Misc methods.  */
+  void deep_copy (const value_range_equiv *);
+  void dump (FILE *) const;
+  void dump () const;
+
+ private:
+  /* Deep-copies bitmap argument.  */
+  void set_equiv (bitmap);
+  void check ();
+
+  /* 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;
+};
+
+extern void dump_value_range (FILE *, const value_range_equiv *);
+
+#endif // GCC_VALUE_RANGE_EQUIV_H
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index b4ab4e6f5b8..cfe4f64809e 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -20,6 +20,8 @@  along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_VR_VALUES_H
 #define GCC_VR_VALUES_H
 
+#include "value-range-equiv.h"
+
 /* The VR_VALUES class holds the current view of range information
    for all the SSA_NAMEs in the IL.