diff options
Diffstat (limited to 'gcc/value-relation.cc')
-rw-r--r-- | gcc/value-relation.cc | 243 |
1 files changed, 231 insertions, 12 deletions
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc index 1ee6da1..50fc190 100644 --- a/gcc/value-relation.cc +++ b/gcc/value-relation.cc @@ -32,10 +32,11 @@ along with GCC; see the file COPYING3. If not see #include "alloc-pool.h" #include "dominance.h" -#define VREL_LAST VREL_NE +#define VREL_LAST VREL_PE64 static const char *kind_string[VREL_LAST + 1] = -{ "varying", "undefined", "<", "<=", ">", ">=", "==", "!=" }; +{ "varying", "undefined", "<", "<=", ">", ">=", "==", "!=", "pe8", "pe16", + "pe32", "pe64" }; // Print a relation_kind REL to file F. @@ -302,7 +303,7 @@ equiv_chain::dump (FILE *f) const bitmap_iterator bi; unsigned i; - if (!m_names) + if (!m_names || bitmap_empty_p (m_names)) return; fprintf (f, "Equivalence set : ["); unsigned c = 0; @@ -329,18 +330,124 @@ equiv_oracle::equiv_oracle () obstack_init (&m_chain_obstack); m_self_equiv.create (0); m_self_equiv.safe_grow_cleared (num_ssa_names + 1); + m_partial.create (0); + m_partial.safe_grow_cleared (num_ssa_names + 1); } // Destruct an equivalency oracle. equiv_oracle::~equiv_oracle () { + m_partial.release (); m_self_equiv.release (); obstack_free (&m_chain_obstack, NULL); m_equiv.release (); bitmap_obstack_release (&m_bitmaps); } +// Add a partial equivalence R between OP1 and OP2. + +void +equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2) +{ + int v1 = SSA_NAME_VERSION (op1); + int v2 = SSA_NAME_VERSION (op2); + int prec2 = TYPE_PRECISION (TREE_TYPE (op2)); + int bits = pe_to_bits (r); + gcc_checking_assert (bits && prec2 >= bits); + + if (v1 >= (int)m_partial.length () || v2 >= (int)m_partial.length ()) + m_partial.safe_grow_cleared (num_ssa_names + 1); + gcc_checking_assert (v1 < (int)m_partial.length () + && v2 < (int)m_partial.length ()); + + pe_slice &pe1 = m_partial[v1]; + pe_slice &pe2 = m_partial[v2]; + + if (pe1.members) + { + // If the definition pe1 already has an entry, either the stmt is + // being re-evaluated, or the def was used before being registered. + // In either case, if PE2 has an entry, we simply do nothing. + if (pe2.members) + return; + // PE1 is the LHS and already has members, so everything in the set + // should be a slice of PE2 rather than PE1. + pe2.code = pe_min (r, pe1.code); + pe2.ssa_base = op2; + pe2.members = pe1.members; + bitmap_iterator bi; + unsigned x; + EXECUTE_IF_SET_IN_BITMAP (pe1.members, 0, x, bi) + { + m_partial[x].ssa_base = op2; + m_partial[x].code = pe2.code; + } + bitmap_set_bit (pe1.members, v2); + return; + } + if (pe2.members) + { + pe1.ssa_base = pe2.ssa_base; + // If pe2 is a 16 bit value, but only an 8 bit copy, we can't be any + // more than an 8 bit equivalence here, so choose MIN value. + pe1.code = pe_min (r, pe2.code); + pe1.members = pe2.members; + bitmap_set_bit (pe1.members, v1); + } + else + { + // Neither name has an entry, simply create op1 as slice of op2. + pe2.code = bits_to_pe (TYPE_PRECISION (TREE_TYPE (op2))); + if (pe2.code == VREL_VARYING) + return; + pe2.ssa_base = op2; + pe2.members = BITMAP_ALLOC (&m_bitmaps); + bitmap_set_bit (pe2.members, v2); + pe1.ssa_base = op2; + pe1.code = r; + pe1.members = pe2.members; + bitmap_set_bit (pe1.members, v1); + } +} + +// Return the set of partial equivalences associated with NAME. The bitmap +// will be NULL if there are none. + +const pe_slice * +equiv_oracle::partial_equiv_set (tree name) +{ + int v = SSA_NAME_VERSION (name); + if (v >= (int)m_partial.length ()) + return NULL; + return &m_partial[v]; +} + +// Query if there is a partial equivalence between SSA1 and SSA2. Return +// VREL_VARYING if there is not one. If BASE is non-null, return the base +// ssa-name this is a slice of. + +relation_kind +equiv_oracle::partial_equiv (tree ssa1, tree ssa2, tree *base) const +{ + int v1 = SSA_NAME_VERSION (ssa1); + int v2 = SSA_NAME_VERSION (ssa2); + + if (v1 >= (int)m_partial.length () || v2 >= (int)m_partial.length ()) + return VREL_VARYING; + + const pe_slice &pe1 = m_partial[v1]; + const pe_slice &pe2 = m_partial[v2]; + if (pe1.members && pe2.members == pe1.members) + { + if (base) + *base = pe1.ssa_base; + return pe_min (pe1.code, pe2.code); + } + return VREL_VARYING; +} + + // Find and return the equivalency set for SSA along the dominators of BB. // This is the external API. @@ -365,7 +472,7 @@ equiv_oracle::equiv_set (tree ssa, basic_block bb) return m_self_equiv[v]; } -// Query if thre is a relation (equivalence) between 2 SSA_NAMEs. +// Query if there is a relation (equivalence) between 2 SSA_NAMEs. relation_kind equiv_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) @@ -373,7 +480,9 @@ equiv_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) // If the 2 ssa names share the same equiv set, they are equal. if (equiv_set (ssa1, bb) == equiv_set (ssa2, bb)) return VREL_EQ; - return VREL_VARYING; + + // Check if there is a partial equivalence. + return partial_equiv (ssa1, ssa2); } // Query if thre is a relation (equivalence) between 2 SSA_NAMEs. @@ -515,6 +624,12 @@ void equiv_oracle::register_relation (basic_block bb, relation_kind k, tree ssa1, tree ssa2) { + // Process partial equivalencies. + if (relation_partial_equiv_p (k)) + { + add_partial_equiv (k, ssa1, ssa2); + return; + } // Only handle equality relations. if (k != VREL_EQ) return; @@ -611,12 +726,34 @@ 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); + // Process equivalences. + if (m_equiv[bb->index]) + { + equiv_chain *ptr = m_equiv[bb->index]->m_next; + for (; ptr; ptr = ptr->m_next) + ptr->dump (f); + } + // Look for partial equivalences defined in this block.. + for (unsigned i = 0; i < num_ssa_names; i++) + { + tree name = ssa_name (i); + if (!gimple_range_ssa_p (name) || !SSA_NAME_DEF_STMT (name)) + continue; + if (i >= m_partial.length ()) + break; + tree base = m_partial[i].ssa_base; + if (base && name != base && gimple_bb (SSA_NAME_DEF_STMT (name)) == bb) + { + relation_kind k = partial_equiv (name, base); + if (k != VREL_VARYING) + { + value_relation vr (k, name, base); + fprintf (f, "Partial equiv "); + vr.dump (f); + fputc ('\n',f); + } + } + } } // Dump all equivalence sets known to the oracle. @@ -906,7 +1043,7 @@ dom_oracle::register_relation (basic_block bb, relation_kind k, tree op1, return; // Equivalencies are handled by the equivalence oracle. - if (k == VREL_EQ) + if (relation_equiv_p (k)) equiv_oracle::register_relation (bb, k, op1, op2); else { @@ -1210,6 +1347,10 @@ dom_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) if (bitmap_bit_p (equiv1, v2) && bitmap_bit_p (equiv2, v1)) return VREL_EQ; + kind = partial_equiv (ssa1, ssa2); + if (kind != VREL_VARYING) + return kind; + // Initially look for a direct relationship and just return that. kind = find_relation_dom (bb, v1, v2); if (kind != VREL_VARYING) @@ -1500,3 +1641,81 @@ path_oracle::dump (FILE *f) const fprintf (f, "\n"); } } + +// ------------------------------------------------------------------------ +// EQUIV iterator. Although we have bitmap iterators, don't expose that it +// is currently a bitmap. Use an export iterator to hide future changes. + +// Construct a basic iterator over an equivalence bitmap. + +equiv_relation_iterator::equiv_relation_iterator (relation_oracle *oracle, + basic_block bb, tree name, + bool full, bool partial) +{ + m_name = name; + m_oracle = oracle; + m_pe = partial ? oracle->partial_equiv_set (name) : NULL; + m_bm = NULL; + if (full) + m_bm = oracle->equiv_set (name, bb); + if (!m_bm && m_pe) + m_bm = m_pe->members; + if (m_bm) + bmp_iter_set_init (&m_bi, m_bm, 1, &m_y); +} + +// Move to the next export bitmap spot. + +void +equiv_relation_iterator::next () +{ + bmp_iter_next (&m_bi, &m_y); +} + +// Fetch the name of the next export in the export list. Return NULL if +// iteration is done. + +tree +equiv_relation_iterator::get_name (relation_kind *rel) +{ + if (!m_bm) + return NULL_TREE; + + while (bmp_iter_set (&m_bi, &m_y)) + { + // Do not return self. + tree t = ssa_name (m_y); + if (t && t != m_name) + { + relation_kind k = VREL_EQ; + if (m_pe && m_bm == m_pe->members) + { + const pe_slice *equiv_pe = m_oracle->partial_equiv_set (t); + if (equiv_pe && equiv_pe->members == m_pe->members) + k = pe_min (m_pe->code, equiv_pe->code); + else + k = VREL_VARYING; + } + if (relation_equiv_p (k)) + { + if (rel) + *rel = k; + return t; + } + } + next (); + } + + // Process partial equivs after full equivs if both were requested. + if (m_pe && m_bm != m_pe->members) + { + m_bm = m_pe->members; + if (m_bm) + { + // Recursively call back to process First PE. + bmp_iter_set_init (&m_bi, m_bm, 1, &m_y); + return get_name (rel); + } + } + return NULL_TREE; +} |