aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-range-equiv.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/value-range-equiv.cc')
-rw-r--r--gcc/value-range-equiv.cc322
1 files changed, 322 insertions, 0 deletions
diff --git a/gcc/value-range-equiv.cc b/gcc/value-range-equiv.cc
new file mode 100644
index 0000000..24132e3
--- /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);
+}