aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-relation.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-09-13 10:37:49 -0700
committerIan Lance Taylor <iant@golang.org>2021-09-13 10:37:49 -0700
commite252b51ccde010cbd2a146485d8045103cd99533 (patch)
treee060f101cdc32bf5e520de8e5275db9d4236b74c /gcc/value-relation.cc
parentf10c7c4596dda99d2ee872c995ae4aeda65adbdf (diff)
parent104c05c5284b7822d770ee51a7d91946c7e56d50 (diff)
downloadgcc-e252b51ccde010cbd2a146485d8045103cd99533.zip
gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.gz
gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.bz2
Merge from trunk revision 104c05c5284b7822d770ee51a7d91946c7e56d50.
Diffstat (limited to 'gcc/value-relation.cc')
-rw-r--r--gcc/value-relation.cc1172
1 files changed, 1172 insertions, 0 deletions
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
new file mode 100644
index 0000000..ba01d29
--- /dev/null
+++ b/gcc/value-relation.cc
@@ -0,0 +1,1172 @@
+/* Header file for the value range relational processing.
+ Copyright (C) 2020-2021 Free Software Foundation, Inc.
+ Contributed by Andrew MacLeod <amacleod@redhat.com>
+
+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 "gimple-range.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "alloc-pool.h"
+#include "dominance.h"
+
+// These VREL codes are arranged such that VREL_NONE is the first
+// code, and all the rest are contiguous up to and including VREL_LAST.
+
+#define VREL_FIRST VREL_NONE
+#define VREL_LAST NE_EXPR
+#define VREL_COUNT (VREL_LAST - VREL_FIRST + 1)
+
+// vrel_range_assert will either assert that the tree code passed is valid,
+// or mark invalid codes as unreachable to help with table optimation.
+#if CHECKING_P
+ #define vrel_range_assert(c) \
+ gcc_checking_assert ((c) >= VREL_FIRST && (c) <= VREL_LAST)
+#else
+ #define vrel_range_assert(c) \
+ if ((c) < VREL_FIRST || (c) > VREL_LAST) \
+ gcc_unreachable ();
+#endif
+
+static const char *kind_string[VREL_COUNT] =
+{ "none", "<", "<=", ">", ">=", "empty", "==", "!=" };
+
+// Print a relation_kind REL to file F.
+
+void
+print_relation (FILE *f, relation_kind rel)
+{
+ vrel_range_assert (rel);
+ fprintf (f, " %s ", kind_string[rel - VREL_FIRST]);
+}
+
+// This table is used to negate the operands. op1 REL op2 -> !(op1 REL op2).
+relation_kind rr_negate_table[VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+ VREL_NONE, GE_EXPR, GT_EXPR, LE_EXPR, LT_EXPR, VREL_EMPTY, NE_EXPR, EQ_EXPR };
+
+// Negate the relation, as in logical negation.
+
+relation_kind
+relation_negate (relation_kind r)
+{
+ vrel_range_assert (r);
+ return rr_negate_table [r - VREL_FIRST];
+}
+
+// This table is used to swap the operands. op1 REL op2 -> op2 REL op1.
+relation_kind rr_swap_table[VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+ VREL_NONE, GT_EXPR, GE_EXPR, LT_EXPR, LE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR };
+
+// Return the relation as if the operands were swapped.
+
+relation_kind
+relation_swap (relation_kind r)
+{
+ vrel_range_assert (r);
+ return rr_swap_table [r - VREL_FIRST];
+}
+
+// This table is used to perform an intersection between 2 relations.
+
+relation_kind rr_intersect_table[VREL_COUNT][VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+// VREL_NONE
+ { VREL_NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR },
+// LT_EXPR
+ { LT_EXPR, LT_EXPR, LT_EXPR, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, LT_EXPR },
+// LE_EXPR
+ { LE_EXPR, LT_EXPR, LE_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, LT_EXPR },
+// GT_EXPR
+ { GT_EXPR, VREL_EMPTY, VREL_EMPTY, GT_EXPR, GT_EXPR, VREL_EMPTY, VREL_EMPTY, GT_EXPR },
+// GE_EXPR
+ { GE_EXPR, VREL_EMPTY, EQ_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, GT_EXPR },
+// VREL_EMPTY
+ { VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY },
+// EQ_EXPR
+ { EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY },
+// NE_EXPR
+ { NE_EXPR, LT_EXPR, LT_EXPR, GT_EXPR, GT_EXPR, VREL_EMPTY, VREL_EMPTY, NE_EXPR } };
+
+
+// Intersect relation R1 with relation R2 and return the resulting relation.
+
+relation_kind
+relation_intersect (relation_kind r1, relation_kind r2)
+{
+ vrel_range_assert (r1);
+ vrel_range_assert (r2);
+ return rr_intersect_table[r1 - VREL_FIRST][r2 - VREL_FIRST];
+}
+
+
+// This table is used to perform a union between 2 relations.
+
+relation_kind rr_union_table[VREL_COUNT][VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+// VREL_NONE
+ { VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE },
+// LT_EXPR
+ { VREL_NONE, LT_EXPR, LE_EXPR, NE_EXPR, VREL_NONE, LT_EXPR, LE_EXPR, NE_EXPR },
+// LE_EXPR
+ { VREL_NONE, LE_EXPR, LE_EXPR, VREL_NONE, VREL_NONE, LE_EXPR, LE_EXPR, VREL_NONE },
+// GT_EXPR
+ { VREL_NONE, NE_EXPR, VREL_NONE, GT_EXPR, GE_EXPR, GT_EXPR, GE_EXPR, NE_EXPR },
+// GE_EXPR
+ { VREL_NONE, VREL_NONE, VREL_NONE, GE_EXPR, GE_EXPR, GE_EXPR, GE_EXPR, VREL_NONE },
+// VREL_EMPTY
+ { VREL_NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR },
+// EQ_EXPR
+ { VREL_NONE, LE_EXPR, LE_EXPR, GE_EXPR, GE_EXPR, EQ_EXPR, EQ_EXPR, VREL_NONE },
+// NE_EXPR
+ { VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR } };
+
+// Union relation R1 with relation R2 and return the result.
+
+relation_kind
+relation_union (relation_kind r1, relation_kind r2)
+{
+ vrel_range_assert (r1);
+ vrel_range_assert (r2);
+ return rr_union_table[r1 - VREL_FIRST][r2 - VREL_FIRST];
+}
+
+
+// This table is used to determine transitivity between 2 relations.
+// (A relation0 B) and (B relation1 C) implies (A result C)
+
+relation_kind rr_transitive_table[VREL_COUNT][VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+// VREL_NONE
+ { VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE },
+// LT_EXPR
+ { VREL_NONE, LT_EXPR, LT_EXPR, VREL_NONE, VREL_NONE, VREL_NONE, LT_EXPR, VREL_NONE },
+// LE_EXPR
+ { VREL_NONE, LT_EXPR, LE_EXPR, VREL_NONE, VREL_NONE, VREL_NONE, LE_EXPR, VREL_NONE },
+// GT_EXPR
+ { VREL_NONE, VREL_NONE, VREL_NONE, GT_EXPR, GT_EXPR, VREL_NONE, GT_EXPR, VREL_NONE },
+// GE_EXPR
+ { VREL_NONE, VREL_NONE, VREL_NONE, GT_EXPR, GE_EXPR, VREL_NONE, GE_EXPR, VREL_NONE },
+// VREL_EMPTY
+ { VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE },
+// EQ_EXPR
+ { VREL_NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, VREL_NONE, EQ_EXPR, VREL_NONE },
+// NE_EXPR
+ { VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE } };
+
+// Apply transitive operation between relation R1 and relation R2, and
+// return the resulting relation, if any.
+
+relation_kind
+relation_transitive (relation_kind r1, relation_kind r2)
+{
+ vrel_range_assert (r1);
+ vrel_range_assert (r2);
+ return rr_transitive_table[r1 - VREL_FIRST][r2 - VREL_FIRST];
+}
+
+// -------------------------------------------------------------------------
+
+// This class represents an equivalency set, and contains a link to the next
+// one in the list to be searched.
+
+// The very first element in the m_equiv chain is actually just a summary
+// element in which the m_names bitmap is used to indicate that an ssa_name
+// has an equivalence set in this block.
+// This allows for much faster traversal of the DOM chain, as a search for
+// SSA_NAME simply requires walking the DOM chain until a block is found
+// which has the bit for SSA_NAME set. Then scan for the equivalency set in
+// that block. No previous blcoks need be searched.
+
+class equiv_chain
+{
+public:
+ bitmap m_names; // ssa-names in equiv set.
+ basic_block m_bb; // Block this belongs to
+ equiv_chain *m_next; // Next in block list.
+ void dump (FILE *f) const; // Show names in this list.
+};
+
+
+// Dump the names in this equivalence set.
+
+void
+equiv_chain::dump (FILE *f) const
+{
+ bitmap_iterator bi;
+ unsigned i;
+
+ if (!m_names)
+ return;
+ fprintf (f, "Equivalence set : [");
+ unsigned c = 0;
+ EXECUTE_IF_SET_IN_BITMAP (m_names, 0, i, bi)
+ {
+ if (ssa_name (i))
+ {
+ if (c++)
+ fprintf (f, ", ");
+ print_generic_expr (f, ssa_name (i), TDF_SLIM);
+ }
+ }
+ fprintf (f, "]\n");
+}
+
+// Instantiate an equivalency oracle.
+
+equiv_oracle::equiv_oracle ()
+{
+ bitmap_obstack_initialize (&m_bitmaps);
+ m_equiv.create (0);
+ m_equiv.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+ m_equiv_set = BITMAP_ALLOC (&m_bitmaps);
+ obstack_init (&m_chain_obstack);
+}
+
+// Destruct an equivalency oracle.
+
+equiv_oracle::~equiv_oracle ()
+{
+ obstack_free (&m_chain_obstack, NULL);
+ m_equiv.release ();
+ bitmap_obstack_release (&m_bitmaps);
+}
+
+// Find and return the equivalency set for SSA along the dominators of BB.
+// This is the external API.
+
+const_bitmap
+equiv_oracle::equiv_set (tree ssa, basic_block bb) const
+{
+ // Search the dominator tree for an equivalency.
+ equiv_chain *equiv = find_equiv_dom (ssa, bb);
+ if (equiv)
+ return equiv->m_names;
+
+ return NULL;
+}
+
+
+// If SSA has an equivalence in block BB, find and return it.
+// Otherwise return NULL.
+
+equiv_chain *
+equiv_oracle::find_equiv_block (unsigned ssa, int bb) const
+{
+ equiv_chain *ptr = NULL;
+ if (bb >= (int)m_equiv.length ())
+ return NULL;
+
+ // If there are equiv sets and SSA is in one in this block, find it.
+ // Otherwise return NULL.
+ if (m_equiv[bb] && bitmap_bit_p (m_equiv[bb]->m_names, ssa))
+ {
+ for (ptr = m_equiv[bb]->m_next; ptr; ptr = ptr->m_next)
+ if (bitmap_bit_p (ptr->m_names, ssa))
+ break;
+ }
+ return ptr;
+}
+
+// Starting at block BB, walk the dominator chain looking for the nearest
+// equivalence set containing NAME.
+
+equiv_chain *
+equiv_oracle::find_equiv_dom (tree name, basic_block bb) const
+{
+ unsigned v = SSA_NAME_VERSION (name);
+ // Short circuit looking for names which have no equivalences.
+ // Saves time looking for something which does not exist.
+ if (!bitmap_bit_p (m_equiv_set, v))
+ return NULL;
+
+ // NAME has at least once equivalence set, check to see if it has one along
+ // the dominator tree.
+ for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ {
+ equiv_chain *ptr = find_equiv_block (v, bb->index);
+ if (ptr)
+ return ptr;
+ }
+ return NULL;
+}
+
+// Register equivalance between ssa_name V and set EQUIV in block BB,
+
+bitmap
+equiv_oracle::register_equiv (basic_block bb, unsigned v, equiv_chain *equiv)
+{
+ // V will have an equivalency now.
+ bitmap_set_bit (m_equiv_set, v);
+
+ // If that equiv chain is in this block, simply use it.
+ if (equiv->m_bb == bb)
+ {
+ bitmap_set_bit (equiv->m_names, v);
+ bitmap_set_bit (m_equiv[bb->index]->m_names, v);
+ return NULL;
+ }
+
+ // Otherwise create an equivalence for this block which is a copy
+ // of equiv, the add V to the set.
+ bitmap b = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_copy (b, equiv->m_names);
+ bitmap_set_bit (b, v);
+ return b;
+}
+
+// Register equivalence between set equiv_1 and equiv_2 in block BB.
+// Return NULL if either name can be merged with the other. Otherwise
+// return a pointer to the combined bitmap of names. This allows the
+// caller to do any setup required for a new element.
+
+bitmap
+equiv_oracle::register_equiv (basic_block bb, equiv_chain *equiv_1,
+ equiv_chain *equiv_2)
+{
+ // If equiv_1 is alreayd in BB, use it as the combined set.
+ if (equiv_1->m_bb == bb)
+ {
+ bitmap_ior_into (equiv_1->m_names, equiv_2->m_names);
+ // Its hard to delete from a single linked list, so
+ // just clear the second one.
+ if (equiv_2->m_bb == bb)
+ bitmap_clear (equiv_2->m_names);
+ else
+ // Ensure equiv_2s names are in the summary for BB.
+ bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_2->m_names);
+ return NULL;
+ }
+ // If equiv_2 is in BB, use it for the combined set.
+ if (equiv_2->m_bb == bb)
+ {
+ bitmap_ior_into (equiv_2->m_names, equiv_1->m_names);
+ // Add equiv_1 names into the summary.
+ bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_1->m_names);
+ return NULL;
+ }
+
+ // At this point, neither equivalence is from this block.
+ bitmap b = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_copy (b, equiv_1->m_names);
+ bitmap_ior_into (b, equiv_2->m_names);
+ return b;
+}
+
+
+// Register an equivalence between SSA1 and SSA2 in block BB.
+// The equivalence oracle maintains a vector of equivalencies indexed by basic
+// block. When an equivalence bteween SSA1 and SSA2 is registered in block BB,
+// a query is made as to what equivalences both names have already, and
+// any preexisting equivalences are merged to create a single equivalence
+// containing all the ssa_names in this basic block.
+
+void
+equiv_oracle::register_equiv (basic_block bb, tree ssa1, tree ssa2)
+{
+ unsigned v1 = SSA_NAME_VERSION (ssa1);
+ unsigned v2 = SSA_NAME_VERSION (ssa2);
+ equiv_chain *equiv_1 = find_equiv_dom (ssa1, bb);
+ equiv_chain *equiv_2 = find_equiv_dom (ssa2, bb);
+
+ // Check if they are the same set
+ if (equiv_1 && equiv_1 == equiv_2)
+ return;
+
+ bitmap equiv_set;
+
+ // Case where we have 2 SSA_NAMEs that are not in any set.
+ if (!equiv_1 && !equiv_2)
+ {
+ bitmap_set_bit (m_equiv_set, v1);
+ bitmap_set_bit (m_equiv_set, v2);
+
+ equiv_set = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_set_bit (equiv_set, v1);
+ bitmap_set_bit (equiv_set, v2);
+ }
+ else if (!equiv_1 && equiv_2)
+ equiv_set = register_equiv (bb, v1, equiv_2);
+ else if (equiv_1 && !equiv_2)
+ equiv_set = register_equiv (bb, v2, equiv_1);
+ else
+ equiv_set = register_equiv (bb, equiv_1, equiv_2);
+
+ // A non-null return is a bitmap that is to be added to the current
+ // block as a new equivalence.
+ if (!equiv_set)
+ return;
+
+ equiv_chain *ptr;
+
+ // Check if this is the first time a block has an equivalence added.
+ // and create a header block. And set the summary for this block.
+ if (!m_equiv[bb->index])
+ {
+ ptr = (equiv_chain *) obstack_alloc (&m_chain_obstack,
+ sizeof (equiv_chain));
+ ptr->m_names = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_copy (ptr->m_names, equiv_set);
+ ptr->m_bb = bb;
+ ptr->m_next = NULL;
+ m_equiv[bb->index] = ptr;
+ }
+
+ // Now create the element for this equiv set and initialize it.
+ ptr = (equiv_chain *) obstack_alloc (&m_chain_obstack, sizeof (equiv_chain));
+ ptr->m_names = equiv_set;
+ ptr->m_bb = bb;
+ gcc_checking_assert (bb->index < (int)m_equiv.length ());
+ ptr->m_next = m_equiv[bb->index]->m_next;
+ m_equiv[bb->index]->m_next = ptr;
+ bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_set);
+}
+
+// Make sure the BB vector is big enough and grow it if needed.
+
+void
+equiv_oracle::limit_check (basic_block bb)
+{
+ int i = (bb) ? bb->index : last_basic_block_for_fn (cfun);
+ if (i >= (int)m_equiv.length ())
+ m_equiv.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+}
+
+// Dump the equivalence sets in BB to file F.
+
+void
+equiv_oracle::dump (FILE *f, basic_block bb) const
+{
+ if (bb->index >= (int)m_equiv.length ())
+ return;
+ if (!m_equiv[bb->index])
+ return;
+
+ equiv_chain *ptr = m_equiv[bb->index]->m_next;
+ for (; ptr; ptr = ptr->m_next)
+ ptr->dump (f);
+}
+
+// Dump all equivalence sets known to the oracle.
+
+void
+equiv_oracle::dump (FILE *f) const
+{
+ fprintf (f, "Equivalency dump\n");
+ for (unsigned i = 0; i < m_equiv.length (); i++)
+ if (m_equiv[i] && BASIC_BLOCK_FOR_FN (cfun, i))
+ {
+ fprintf (f, "BB%d\n", i);
+ dump (f, BASIC_BLOCK_FOR_FN (cfun, i));
+ }
+}
+
+
+// --------------------------------------------------------------------------
+
+// The value-relation class is used to encapsulate the represention of an
+// individual relation between 2 ssa-names, and to facilitate operating on
+// the relation.
+
+class value_relation
+{
+public:
+ value_relation ();
+ value_relation (relation_kind kind, tree n1, tree n2);
+ void set_relation (relation_kind kind, tree n1, tree n2);
+
+ inline relation_kind kind () const { return related; }
+ inline tree op1 () const { return name1; }
+ inline tree op2 () const { return name2; }
+
+ bool union_ (value_relation &p);
+ bool intersect (value_relation &p);
+ void negate ();
+ bool apply_transitive (const value_relation &rel);
+
+ void dump (FILE *f) const;
+private:
+ relation_kind related;
+ tree name1, name2;
+};
+
+// Set relation R between ssa_name N1 and N2.
+
+inline void
+value_relation::set_relation (relation_kind r, tree n1, tree n2)
+{
+ gcc_checking_assert (SSA_NAME_VERSION (n1) != SSA_NAME_VERSION (n2));
+ related = r;
+ name1 = n1;
+ name2 = n2;
+}
+
+// Default constructor.
+
+inline
+value_relation::value_relation ()
+{
+ related = VREL_NONE;
+ name1 = NULL_TREE;
+ name2 = NULL_TREE;
+}
+
+// Constructor for relation R between SSA version N1 nd N2.
+
+inline
+value_relation::value_relation (relation_kind kind, tree n1, tree n2)
+{
+ set_relation (kind, n1, n2);
+}
+
+// Negate the current relation.
+
+void
+value_relation::negate ()
+{
+ related = relation_negate (related);
+}
+
+// Perform an intersection between 2 relations. *this &&= p.
+
+bool
+value_relation::intersect (value_relation &p)
+{
+ // Save previous value
+ relation_kind old = related;
+
+ if (p.op1 () == op1 () && p.op2 () == op2 ())
+ related = relation_intersect (kind (), p.kind ());
+ else if (p.op2 () == op1 () && p.op1 () == op2 ())
+ related = relation_intersect (kind (), relation_swap (p.kind ()));
+ else
+ return false;
+
+ return old != related;
+}
+
+// Perform a union between 2 relations. *this ||= p.
+
+bool
+value_relation::union_ (value_relation &p)
+{
+ // Save previous value
+ relation_kind old = related;
+
+ if (p.op1 () == op1 () && p.op2 () == op2 ())
+ related = relation_union (kind(), p.kind());
+ else if (p.op2 () == op1 () && p.op1 () == op2 ())
+ related = relation_union (kind(), relation_swap (p.kind ()));
+ else
+ return false;
+
+ return old != related;
+}
+
+// Identify and apply any transitive relations between REL
+// and THIS. Return true if there was a transformation.
+
+bool
+value_relation::apply_transitive (const value_relation &rel)
+{
+ relation_kind k = VREL_NONE;
+
+ // Idenity any common operand, and notrmalize the relations to
+ // the form : A < B B < C produces A < C
+ if (rel.op1 () == name2)
+ {
+ // A < B B < C
+ if (rel.op2 () == name1)
+ return false;
+ k = relation_transitive (kind (), rel.kind ());
+ if (k != VREL_NONE)
+ {
+ related = k;
+ name2 = rel.op2 ();
+ return true;
+ }
+ }
+ else if (rel.op1 () == name1)
+ {
+ // B > A B < C
+ if (rel.op2 () == name2)
+ return false;
+ k = relation_transitive (relation_swap (kind ()), rel.kind ());
+ if (k != VREL_NONE)
+ {
+ related = k;
+ name1 = name2;
+ name2 = rel.op2 ();
+ return true;
+ }
+ }
+ else if (rel.op2 () == name2)
+ {
+ // A < B C > B
+ if (rel.op1 () == name1)
+ return false;
+ k = relation_transitive (kind (), relation_swap (rel.kind ()));
+ if (k != VREL_NONE)
+ {
+ related = k;
+ name2 = rel.op1 ();
+ return true;
+ }
+ }
+ else if (rel.op2 () == name1)
+ {
+ // B > A C > B
+ if (rel.op1 () == name2)
+ return false;
+ k = relation_transitive (relation_swap (kind ()),
+ relation_swap (rel.kind ()));
+ if (k != VREL_NONE)
+ {
+ related = k;
+ name1 = name2;
+ name2 = rel.op1 ();
+ return true;
+ }
+ }
+ return false;
+}
+
+// Dump the relation to file F.
+
+void
+value_relation::dump (FILE *f) const
+{
+ if (!name1 || !name2)
+ {
+ fprintf (f, "uninitialized");
+ return;
+ }
+ fputc ('(', f);
+ print_generic_expr (f, op1 (), TDF_SLIM);
+ print_relation (f, kind ());
+ print_generic_expr (f, op2 (), TDF_SLIM);
+ fputc(')', f);
+}
+
+// This container is used to link relations in a chain.
+
+class relation_chain : public value_relation
+{
+public:
+ relation_chain *m_next;
+};
+
+// ------------------------------------------------------------------------
+
+// Instantiate a relation oracle.
+
+relation_oracle::relation_oracle ()
+{
+ m_relations.create (0);
+ m_relations.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+ m_relation_set = BITMAP_ALLOC (&m_bitmaps);
+ m_tmp = BITMAP_ALLOC (&m_bitmaps);
+ m_tmp2 = BITMAP_ALLOC (&m_bitmaps);
+}
+
+// Destruct a relation oracle.
+
+relation_oracle::~relation_oracle ()
+{
+ m_relations.release ();
+}
+
+// Register relation K between ssa_name OP1 and OP2 on STMT.
+
+void
+relation_oracle::register_relation (gimple *stmt, relation_kind k, tree op1,
+ tree op2)
+{
+ gcc_checking_assert (TREE_CODE (op1) == SSA_NAME);
+ gcc_checking_assert (TREE_CODE (op2) == SSA_NAME);
+ gcc_checking_assert (stmt && gimple_bb (stmt));
+
+ // Don't register lack of a relation.
+ if (k == VREL_NONE)
+ return;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ value_relation vr (k, op1, op2);
+ fprintf (dump_file, " Registering value_relation ");
+ vr.dump (dump_file);
+ fprintf (dump_file, " (bb%d) at ", gimple_bb (stmt)->index);
+ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ }
+
+ // This relation applies to the entire block, use STMT's block.
+ // Equivalencies are handled by the equivalence oracle.
+ if (k == EQ_EXPR)
+ register_equiv (gimple_bb (stmt), op1, op2);
+ else
+ register_relation (gimple_bb (stmt), k, op1, op2);
+}
+
+// Register relation K between ssa_name OP1 and OP2 on edge E.
+
+void
+relation_oracle::register_relation (edge e, relation_kind k, tree op1,
+ tree op2)
+{
+ gcc_checking_assert (TREE_CODE (op1) == SSA_NAME);
+ gcc_checking_assert (TREE_CODE (op2) == SSA_NAME);
+
+ // Do not register lack of relation, or blocks which have more than
+ // edge E for a predecessor.
+ if (k == VREL_NONE || !single_pred_p (e->dest))
+ return;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ value_relation vr (k, op1, op2);
+ fprintf (dump_file, " Registering value_relation ");
+ vr.dump (dump_file);
+ fprintf (dump_file, " on (%d->%d)\n", e->src->index, e->dest->index);
+ }
+
+ // Equivalencies are handled by the equivalence oracle.
+ if (k == EQ_EXPR)
+ register_equiv (e->dest, op1, op2);
+ else
+ register_relation (e->dest, k, op1, op2);
+}
+
+// Register relation K between OP! and OP2 in block BB.
+// This creates the record and searches for existing records in the dominator
+// tree to merge with.
+// TRANSITIVE_P is true if this is being registered as a transitive operation,
+// and should not try to register further transitives.
+
+void
+relation_oracle::register_relation (basic_block bb, relation_kind k, tree op1,
+ tree op2, bool transitive_p)
+{
+ gcc_checking_assert (k != VREL_NONE);
+
+ value_relation vr(k, op1, op2);
+ int bbi = bb->index;
+
+ if (bbi >= (int)m_relations.length())
+ m_relations.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+
+ // Summary bitmap indicating what ssa_names have relations in this BB.
+ bitmap bm = m_relations[bbi].m_names;
+ if (!bm)
+ bm = m_relations[bbi].m_names = BITMAP_ALLOC (&m_bitmaps);
+ unsigned v1 = SSA_NAME_VERSION (op1);
+ unsigned v2 = SSA_NAME_VERSION (op2);
+
+ relation_kind curr;
+ relation_chain *ptr;
+ curr = find_relation_block (bbi, v1, v2, &ptr);
+ // There is an existing relation in this block, just intersect with it.
+ if (curr != VREL_NONE)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " Intersecting with existing ");
+ ptr->dump (dump_file);
+ }
+ // Check into whether we can simply replace the relation rather than
+ // intersecting it. THis may help with some optimistic iterative
+ // updating algorithms.
+ ptr->intersect (vr);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " to produce ");
+ ptr->dump (dump_file);
+ fprintf (dump_file, "\n");
+ }
+ }
+ else
+ {
+ // Check for an existing relation further up the DOM chain.
+ // By including dominating relations, The first one found in any search
+ // will be the aggregate of all the previous ones.
+ curr = find_relation_dom (bb, v1, v2);
+ if (curr != VREL_NONE)
+ k = relation_intersect (curr, k);
+
+ bitmap_set_bit (bm, v1);
+ bitmap_set_bit (bm, v2);
+ bitmap_set_bit (m_relation_set, v1);
+ bitmap_set_bit (m_relation_set, v2);
+
+ ptr = (relation_chain *) obstack_alloc (&m_chain_obstack,
+ sizeof (relation_chain));
+ ptr->set_relation (k, op1, op2);
+ ptr->m_next = m_relations[bbi].m_head;
+ m_relations[bbi].m_head = ptr;;
+ }
+
+ if (!transitive_p)
+ register_transitives (bb, *ptr);
+}
+
+// Starting at ROOT_BB search the DOM tree looking for relations which
+// may produce transitive relations to RELATION. EQUIV1 and EQUIV2 are
+// bitmaps for op1/op2 and any of their equivalences that should also be
+// considered.
+
+void
+relation_oracle::register_transitives (basic_block root_bb,
+ const value_relation &relation,
+ const_bitmap equiv1,
+ const_bitmap equiv2)
+{
+ basic_block bb;
+ for (bb = root_bb; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ {
+ int bbi = bb->index;
+ if (bbi >= (int)m_relations.length())
+ continue;
+ const_bitmap bm = m_relations[bbi].m_names;
+ if (!bm)
+ continue;
+ if (!bitmap_intersect_p (bm, equiv1) && !bitmap_intersect_p (bm, equiv2))
+ continue;
+ // At least one of the 2 ops has a relation in this block.
+ relation_chain *ptr;
+ for (ptr = m_relations[bbi].m_head; ptr ; ptr = ptr->m_next)
+ {
+ // In the presence of an equivalence, 2 operands may do not
+ // naturally match. ie with equivalence a_2 == b_3
+ // given c_1 < a_2 && b_3 < d_4
+ // convert the second relation (b_3 < d_4) to match any
+ // equivalences to found in the first relation.
+ // ie convert b_3 < d_4 to a_2 < d_4, which then exposes the
+ // transitive operation: c_1 < a_2 && a_2 < d_4 -> c_1 < d_4
+
+ tree r1, r2;
+ tree p1 = ptr->op1 ();
+ tree p2 = ptr->op2 ();
+ // Find which equivalence is in the first operand.
+ if (bitmap_bit_p (equiv1, SSA_NAME_VERSION (p1)))
+ r1 = p1;
+ else if (bitmap_bit_p (equiv1, SSA_NAME_VERSION (p2)))
+ r1 = p2;
+ else
+ r1 = NULL_TREE;
+
+ // Find which equivalence is in the second operand.
+ if (bitmap_bit_p (equiv2, SSA_NAME_VERSION (p1)))
+ r2 = p1;
+ else if (bitmap_bit_p (equiv2, SSA_NAME_VERSION (p2)))
+ r2 = p2;
+ else
+ r2 = NULL_TREE;
+
+ // Ignore if both NULL (not relevant relation) or the same,
+ if (r1 == r2)
+ continue;
+
+ // Any operand not an equivalence, just take the real operand.
+ if (!r1)
+ r1 = relation.op1 ();
+ if (!r2)
+ r2 = relation.op2 ();
+
+ value_relation nr (relation.kind (), r1, r2);
+ if (nr.apply_transitive (*ptr))
+ {
+ register_relation (root_bb, nr.kind (), nr.op1 (), nr.op2 (),
+ true);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " Registering transitive relation ");
+ nr.dump (dump_file);
+ fputc ('\n', dump_file);
+ }
+ }
+
+ }
+ }
+}
+
+// Find adn register any transitive relations implied by RELATION occuring
+// in block BB.
+
+void
+relation_oracle::register_transitives (basic_block bb,
+ const value_relation &relation)
+{
+ // Only apply transitives to certain kinds of operations.
+ switch (relation.kind ())
+ {
+ case LE_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ break;
+ default:
+ return;
+ }
+
+ // Set up the bitmaps for op1 and op2, and if there are no equivalencies,
+ // set just op1 or op2 in their own bitmap.
+ const_bitmap equiv1 = equiv_set (relation.op1 (), bb);
+ const_bitmap equiv2 = equiv_set (relation.op2 (), bb);
+ if (equiv1)
+ {
+ if (equiv2)
+ register_transitives (bb, relation, equiv1, equiv2);
+ else
+ {
+ bitmap_clear (m_tmp);
+ bitmap_set_bit (m_tmp, SSA_NAME_VERSION (relation.op2 ()));
+ register_transitives (bb, relation, equiv1, m_tmp);
+ }
+ }
+ else if (equiv2)
+ {
+ bitmap_clear (m_tmp);
+ bitmap_set_bit (m_tmp, SSA_NAME_VERSION (relation.op1 ()));
+ register_transitives (bb, relation, m_tmp, equiv2);
+ }
+ else
+ {
+ bitmap_clear (m_tmp);
+ bitmap_clear (m_tmp2);
+ bitmap_set_bit (m_tmp, SSA_NAME_VERSION (relation.op1 ()));
+ bitmap_set_bit (m_tmp2, SSA_NAME_VERSION (relation.op2 ()));
+ register_transitives (bb, relation, m_tmp, m_tmp2);
+ }
+}
+
+// Find the relation between any ssa_name in B1 and any name in B2 in block BB.
+// This will allow equivalencies to be applied to any SSA_NAME in a relation.
+
+relation_kind
+relation_oracle::find_relation_block (unsigned bb, const_bitmap b1,
+ const_bitmap b2)
+{
+ const_bitmap bm;
+ if (bb >= m_relations.length())
+ return VREL_NONE;
+
+ bm = m_relations[bb].m_names;
+ if (!bm)
+ return VREL_NONE;
+
+ // If both b1 and b2 aren't referenced in thie block, cant be a relation
+ if (!bitmap_intersect_p (bm, b1) || !bitmap_intersect_p (bm, b2))
+ return VREL_NONE;
+
+ // Search for the fiorst relation that contains BOTH an element from B1
+ // and B2, and return that relation.
+ for (relation_chain *ptr = m_relations[bb].m_head; ptr ; ptr = ptr->m_next)
+ {
+ unsigned op1 = SSA_NAME_VERSION (ptr->op1 ());
+ unsigned op2 = SSA_NAME_VERSION (ptr->op2 ());
+ if (bitmap_bit_p (b1, op1) && bitmap_bit_p (b2, op2))
+ return ptr->kind ();
+ if (bitmap_bit_p (b1, op2) && bitmap_bit_p (b2, op1))
+ return relation_swap (ptr->kind ());
+ }
+
+ return VREL_NONE;
+}
+
+// Search the DOM tree for a relation between an element of B1 and B2, starting
+// with block BB.
+
+relation_kind
+relation_oracle::find_relation_dom (basic_block bb, const_bitmap b1,
+ const_bitmap b2)
+{
+ relation_kind r;
+ // If either name does not occur in a relation anywhere, there isnt one.
+ if (!bitmap_intersect_p (m_relation_set, b1)
+ || !bitmap_intersect_p (m_relation_set, b2))
+ return VREL_NONE;
+
+ // Search each block in the DOM tree checking.
+ for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ {
+ r = find_relation_block (bb->index, b1, b2);
+ if (r != VREL_NONE)
+ return r;
+ }
+ return VREL_NONE;
+
+}
+
+// Find a relation in block BB between ssa version V1 and V2. If a relation
+// is found, return a pointer to the chain object in OBJ.
+
+relation_kind
+relation_oracle::find_relation_block (int bb, unsigned v1, unsigned v2,
+ relation_chain **obj)
+{
+ if (bb >= (int)m_relations.length())
+ return VREL_NONE;
+
+ const_bitmap bm = m_relations[bb].m_names;
+ if (!bm)
+ return VREL_NONE;
+
+ // If both b1 and b2 aren't referenced in thie block, cant be a relation
+ if (!bitmap_bit_p (bm, v1) || !bitmap_bit_p (bm, v2))
+ return VREL_NONE;
+
+ relation_chain *ptr;
+ for (ptr = m_relations[bb].m_head; ptr ; ptr = ptr->m_next)
+ {
+ unsigned op1 = SSA_NAME_VERSION (ptr->op1 ());
+ unsigned op2 = SSA_NAME_VERSION (ptr->op2 ());
+ if (v1 == op1 && v2 == op2)
+ {
+ if (obj)
+ *obj = ptr;
+ return ptr->kind ();
+ }
+ if (v1 == op2 && v2 == op1)
+ {
+ if (obj)
+ *obj = ptr;
+ return relation_swap (ptr->kind ());
+ }
+ }
+
+ return VREL_NONE;
+}
+
+// Find a relation between SSA version V1 and V2 in the dominator tree
+// starting with block BB
+
+relation_kind
+relation_oracle::find_relation_dom (basic_block bb, unsigned v1, unsigned v2)
+{
+ relation_kind r;
+ // IF either name does not occur in a relation anywhere, there isnt one.
+ if (!bitmap_bit_p (m_relation_set, v1) || !bitmap_bit_p (m_relation_set, v2))
+ return VREL_NONE;
+
+ for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ {
+ r = find_relation_block (bb->index, v1, v2);
+ if (r != VREL_NONE)
+ return r;
+ }
+ return VREL_NONE;
+
+}
+
+// Query if there is a relation between SSA1 and SS2 in block BB or a
+// dominator of BB
+
+relation_kind
+relation_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2)
+{
+ relation_kind kind;
+ unsigned v1 = SSA_NAME_VERSION (ssa1);
+ unsigned v2 = SSA_NAME_VERSION (ssa2);
+ if (v1 == v2)
+ return EQ_EXPR;
+
+ // Check for equivalence first.
+ const_bitmap equiv1 = equiv_set (ssa1, bb);
+ if (equiv1 && bitmap_bit_p (equiv1, v2))
+ return EQ_EXPR;
+
+ // Initially look for a direct relationship and just return that.
+ kind = find_relation_dom (bb, v1, v2);
+ if (kind != VREL_NONE)
+ return kind;
+
+ // If v2 isn't in v1s equiv set, then v1 shouldn't be in v2's set either.
+ // It is possible for out-of-order dominator processing to have an out of
+ // sync set of equivalences.. Down the road, when we do full updates,
+ // change this to an assert to ensure everything is in sync.
+ const_bitmap equiv2 = equiv_set (ssa2, bb);
+ if (equiv2 && bitmap_bit_p (equiv2, v1))
+ return EQ_EXPR;
+
+ // If not equal, see if there is a relationship between equivalences.
+ if (!equiv1 && !equiv2)
+ kind = VREL_NONE;
+ else if (!equiv1)
+ {
+ bitmap_clear (m_tmp);
+ bitmap_set_bit (m_tmp, v1);
+ kind = find_relation_dom (bb, m_tmp, equiv2);
+ }
+ else if (!equiv2)
+ {
+ bitmap_clear (m_tmp);
+ bitmap_set_bit (m_tmp, v2);
+ kind = find_relation_dom (bb, equiv1, m_tmp);
+ }
+ else
+ kind = find_relation_dom (bb, equiv1, equiv2);
+ return kind;
+}
+
+// Dump all the relations in block BB to file F.
+
+void
+relation_oracle::dump (FILE *f, basic_block bb) const
+{
+ equiv_oracle::dump (f,bb);
+
+ if (bb->index >= (int)m_relations.length ())
+ return;
+ if (!m_relations[bb->index].m_names)
+ return;
+
+ relation_chain *ptr = m_relations[bb->index].m_head;
+ for (; ptr; ptr = ptr->m_next)
+ {
+ fprintf (f, "Relational : ");
+ ptr->dump (f);
+ fprintf (f, "\n");
+ }
+}
+
+// Dump all the relations known to file F.
+
+void
+relation_oracle::dump (FILE *f) const
+{
+ fprintf (f, "Relation dump\n");
+ for (unsigned i = 0; i < m_relations.length (); i++)
+ if (BASIC_BLOCK_FOR_FN (cfun, i))
+ {
+ fprintf (f, "BB%d\n", i);
+ dump (f, BASIC_BLOCK_FOR_FN (cfun, i));
+ }
+}
+
+void
+relation_oracle::debug () const
+{
+ dump (stderr);
+}