Add partial equivalence support to the relation oracle.

This provides enhancements to the equivalence oracle to also track
partial equivalences.  They are tracked similar to equivalences, except
it tracks a 'slice' of another ssa name.   8, 16, 32 and 64 bit slices are
tracked.  This will allow casts and mask of the same value to compare
equal.

	* value-relation.cc (equiv_chain::dump): Don't print empty
	equivalences.
	(equiv_oracle::equiv_oracle): Allocate a partial equiv table.
	(equiv_oracle::~equiv_oracle): Release the partial equiv table.
	(equiv_oracle::add_partial_equiv): New.
	(equiv_oracle::partial_equiv_set): New.
	(equiv_oracle::partial_equiv): New.
	(equiv_oracle::query_relation): Check for partial equivs too.
	(equiv_oracle::dump): Also dump partial equivs.
	(dom_oracle::register_relation): Handle partial equivs.
	(dom_oracle::query_relation): Check for partial equivs.
	* value-relation.h (enum relation_kind_t): Add partial equivs.
	(relation_partial_equiv_p): New.
	(relation_equiv_p): New.
	(class pe_slice): New.
	(class equiv_oracle): Add prototypes.
	(pe_to_bits): New.
	(bits_to_pe): New.
	(pe_min): New.
This commit is contained in:
Andrew MacLeod 2022-10-06 15:00:52 -04:00
parent 3130e70dab
commit b5563410ea
2 changed files with 229 additions and 14 deletions

View file

@ -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)

View file

@ -70,7 +70,11 @@ typedef enum relation_kind_t
VREL_GT, // r1 > r2
VREL_GE, // r1 >= r2
VREL_EQ, // r1 == r2
VREL_NE // r1 != r2
VREL_NE, // r1 != r2
VREL_PE8, // 8 bit partial equivalency
VREL_PE16, // 16 bit partial equivalency
VREL_PE32, // 32 bit partial equivalency
VREL_PE64 // 64 bit partial equivalency
} relation_kind;
// General relation kind transformations.
@ -79,7 +83,12 @@ relation_kind relation_intersect (relation_kind r1, relation_kind r2);
relation_kind relation_negate (relation_kind r);
relation_kind relation_swap (relation_kind r);
inline bool relation_lt_le_gt_ge_p (relation_kind r)
{ return (r >= VREL_LT && r <= VREL_GE); }
{ return (r >= VREL_LT && r <= VREL_GE); }
inline bool relation_partial_equiv_p (relation_kind r)
{ return (r >= VREL_PE8 && r <= VREL_PE64); }
inline bool relation_equiv_p (relation_kind r)
{ return r == VREL_EQ || relation_partial_equiv_p (r); }
void print_relation (FILE *f, relation_kind rel);
class relation_oracle
@ -93,6 +102,7 @@ public:
// Return equivalency set for an SSA name in a basic block.
virtual const_bitmap equiv_set (tree, basic_block) = 0;
virtual const class pe_slice *partial_equiv_set (tree) { return NULL; }
// register a relation between 2 ssa names in a basic block.
virtual void register_relation (basic_block, relation_kind, tree, tree) = 0;
// Query for a relation between two ssa names in a basic block.
@ -125,6 +135,14 @@ public:
equiv_chain *find (unsigned ssa);
};
class pe_slice
{
public:
tree ssa_base; // Slice of this name.
relation_kind code; // bits that are equivalent.
bitmap members; // Other members in the partial equivalency.
};
// The equivalency oracle maintains equivalencies using the dominator tree.
// Equivalencies apply to an entire basic block. Equivalencies on edges
// can be represented only on edges whose destination is a single-pred block,
@ -137,9 +155,12 @@ public:
~equiv_oracle ();
const_bitmap equiv_set (tree ssa, basic_block bb) final override;
const pe_slice *partial_equiv_set (tree name) final override;
void register_relation (basic_block bb, relation_kind k, tree ssa1,
tree ssa2) override;
void add_partial_equiv (relation_kind, tree, tree);
relation_kind partial_equiv (tree ssa1, tree ssa2, tree *base = NULL) const;
relation_kind query_relation (basic_block, tree, tree) override;
relation_kind query_relation (basic_block, const_bitmap, const_bitmap)
override;
@ -153,6 +174,7 @@ private:
bitmap m_equiv_set; // Index by ssa-name. true if an equivalence exists.
vec <equiv_chain *> m_equiv; // Index by BB. list of equivalences.
vec <bitmap> m_self_equiv; // Index by ssa-name, self equivalency set.
vec <pe_slice> m_partial; // Partial equivalencies.
void limit_check (basic_block bb = NULL);
equiv_chain *find_equiv_block (unsigned ssa, int bb) const;
@ -315,4 +337,56 @@ value_relation::value_relation (relation_kind kind, tree n1, tree n2)
set_relation (kind, n1, n2);
}
// Return the number of bits associated with partial equivalency T.
// Return 0 if this is not a supported partial equivalency relation.
inline int
pe_to_bits (relation_kind t)
{
switch (t)
{
case VREL_PE8:
return 8;
case VREL_PE16:
return 16;
case VREL_PE32:
return 32;
case VREL_PE64:
return 64;
default:
return 0;
}
}
// Return the partial equivalency code associated with the number of BITS.
// return VREL_VARYING if there is no exact match.
inline relation_kind
bits_to_pe (int bits)
{
switch (bits)
{
case 8:
return VREL_PE8;
case 16:
return VREL_PE16;
case 32:
return VREL_PE32;
case 64:
return VREL_PE64;
default:
return VREL_VARYING;
}
}
// Given partial equivalencies T1 and T2, return the snmallest kind.
inline relation_kind
pe_min (relation_kind t1, relation_kind t2)
{
gcc_checking_assert (relation_partial_equiv_p (t1));
gcc_checking_assert (relation_partial_equiv_p (t2));
// VREL_PE are declared small to large, so simple min will suffice.
return MIN (t1, t2);
}
#endif /* GCC_VALUE_RELATION_H */