From 2f80eb1feb3f92c7e9e57d4726ec52ca7d27ce92 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 30 Apr 2024 09:35:23 -0400
Subject: [PATCH 02/12] Move to an always available relation oracle.
This eliminates the need to check if the relation oracle pointer is NULL
before every call by providing a default oracle which does nothing.
REmove unused routines, and Unify register_relation method names.
* gimple-range-cache.cc (ranger_cache::dump_bb): Remove check for
NULL oracle pointer.
(ranger_cache::fill_block_cache): Likewise.
* gimple-range-fold.cc (fur_stmt::get_phi_operand): Likewise.
(fur_depend::fur_depend): Likewise.
(fur_depend::register_relation): Likewise, use qury_relation.
(fold_using_range::range_of_phi): Likewise.
(fold_using_range::relation_fold_and_or): Likewise.
* gimple-range-fold.h (fur_source::m_oracle): Delete. Oracle
can be accessed dirctly via m_query now.
* gimple-range-path.cc (path_range_query::path_range_query):
Adjust for oracle reference pointer.
(path_range_query::compute_ranges): Likewise.
(jt_fur_source::jt_fur_source): Adjust for no m_oracle member.
(jt_fur_source::register_relation): Do not check for NULL
pointer.
(jt_fur_source::query_relation): Likewise.
* gimple-range.cc (gimple_ranger::gimple_ranger): Adjust for
reference pointer.
* value_query.cc (default_relation_oracle): New.
(range_query::create_relation_oracle): Relocate from header.
Ensure not being added to global query.
(range_query::destroy_relation_oracle): Relocate from header.
(range_query::range_query): Initailize to default oracle.
(ange_query::~range_query): Call destroy_relation_oracle.
* value-query.h (class range_query): Adjust prototypes.
(range_query::create_relation_oracle): Move to source file.
(range_query::destroy_relation_oracle): Move to source file.
* value-relation.cc (relation_oracle::validate_relation): Delete.
(relation_oracle::register_stmt): Rename to register_relation.
(relation_oracle::register_edge): Likewise.
* value-relation.h (register_stmt): Rename to register_relation and
provide default function in base class.
(register_edge): Likewise.
(relation_oracle::query_relation): Provide default in base class.
(relation_oracle::dump): Likewise.
(relation_oracle::equiv_set): Likewise.
(default_relation_oracle): New extenal reference.
(partial_equiv_set, add_partial_equiv): Move to protected.
* value-relation.h (relation_oracle::validate_relation): Delete.
---
gcc/gimple-range-cache.cc | 98 +++++++++++++++++++--------------------
gcc/gimple-range-fold.cc | 22 +++------
gcc/gimple-range-fold.h | 2 -
gcc/gimple-range-path.cc | 22 +++------
gcc/gimple-range.cc | 5 +-
gcc/value-query.cc | 38 +++++++++++++--
gcc/value-query.h | 31 ++-----------
gcc/value-relation.cc | 66 ++------------------------
gcc/value-relation.h | 32 ++++++-------
9 files changed, 119 insertions(+), 197 deletions(-)
@@ -1001,8 +1001,7 @@ ranger_cache::dump_bb (FILE *f, basic_block bb)
{
m_gori.gori_map::dump (f, bb, false);
m_on_entry.dump (f, bb);
- if (m_oracle)
- m_oracle->dump (f, bb);
+ m_oracle->dump (f, bb);
}
// Get the global range for NAME, and return in R. Return false if the
@@ -1437,62 +1436,59 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
// See if any equivalences can refine it.
// PR 109462, like 108139 below, a one way equivalence introduced
// by a PHI node can also be through the definition side. Disallow it.
- if (m_oracle)
+ tree equiv_name;
+ relation_kind rel;
+ int prec = TYPE_PRECISION (type);
+ FOR_EACH_PARTIAL_AND_FULL_EQUIV (m_oracle, bb, name, equiv_name, rel)
{
- tree equiv_name;
- relation_kind rel;
- int prec = TYPE_PRECISION (type);
- FOR_EACH_PARTIAL_AND_FULL_EQUIV (m_oracle, bb, name, equiv_name, rel)
- {
- basic_block equiv_bb = gimple_bb (SSA_NAME_DEF_STMT (equiv_name));
+ basic_block equiv_bb = gimple_bb (SSA_NAME_DEF_STMT (equiv_name));
- // Ignore partial equivs that are smaller than this object.
- if (rel != VREL_EQ && prec > pe_to_bits (rel))
- continue;
+ // Ignore partial equivs that are smaller than this object.
+ if (rel != VREL_EQ && prec > pe_to_bits (rel))
+ continue;
- // Check if the equiv has any ranges calculated.
- if (!m_gori.has_edge_range_p (equiv_name))
- continue;
+ // Check if the equiv has any ranges calculated.
+ if (!m_gori.has_edge_range_p (equiv_name))
+ continue;
- // Check if the equiv definition dominates this block
- if (equiv_bb == bb ||
- (equiv_bb && !dominated_by_p (CDI_DOMINATORS, bb, equiv_bb)))
- continue;
+ // Check if the equiv definition dominates this block
+ if (equiv_bb == bb ||
+ (equiv_bb && !dominated_by_p (CDI_DOMINATORS, bb, equiv_bb)))
+ continue;
- if (DEBUG_RANGE_CACHE)
- {
- if (rel == VREL_EQ)
- fprintf (dump_file, "Checking Equivalence (");
- else
- fprintf (dump_file, "Checking Partial equiv (");
- print_relation (dump_file, rel);
- fprintf (dump_file, ") ");
- print_generic_expr (dump_file, equiv_name, TDF_SLIM);
- fprintf (dump_file, "\n");
- }
- Value_Range equiv_range (TREE_TYPE (equiv_name));
- if (range_from_dom (equiv_range, equiv_name, bb, RFD_READ_ONLY))
- {
- if (rel != VREL_EQ)
- range_cast (equiv_range, type);
- else
- adjust_equivalence_range (equiv_range);
+ if (DEBUG_RANGE_CACHE)
+ {
+ if (rel == VREL_EQ)
+ fprintf (dump_file, "Checking Equivalence (");
+ else
+ fprintf (dump_file, "Checking Partial equiv (");
+ print_relation (dump_file, rel);
+ fprintf (dump_file, ") ");
+ print_generic_expr (dump_file, equiv_name, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ Value_Range equiv_range (TREE_TYPE (equiv_name));
+ if (range_from_dom (equiv_range, equiv_name, bb, RFD_READ_ONLY))
+ {
+ if (rel != VREL_EQ)
+ range_cast (equiv_range, type);
+ else
+ adjust_equivalence_range (equiv_range);
- if (block_result.intersect (equiv_range))
+ if (block_result.intersect (equiv_range))
+ {
+ if (DEBUG_RANGE_CACHE)
{
- if (DEBUG_RANGE_CACHE)
- {
- if (rel == VREL_EQ)
- fprintf (dump_file, "Equivalence update! : ");
- else
- fprintf (dump_file, "Partial equiv update! : ");
- print_generic_expr (dump_file, equiv_name, TDF_SLIM);
- fprintf (dump_file, " has range : ");
- equiv_range.dump (dump_file);
- fprintf (dump_file, " refining range to :");
- block_result.dump (dump_file);
- fprintf (dump_file, "\n");
- }
+ if (rel == VREL_EQ)
+ fprintf (dump_file, "Equivalence update! : ");
+ else
+ fprintf (dump_file, "Partial equiv update! : ");
+ print_generic_expr (dump_file, equiv_name, TDF_SLIM);
+ fprintf (dump_file, " has range : ");
+ equiv_range.dump (dump_file);
+ fprintf (dump_file, " refining range to :");
+ block_result.dump (dump_file);
+ fprintf (dump_file, "\n");
}
}
}
@@ -178,10 +178,7 @@ fur_stmt::get_phi_operand (vrange &r, tree expr, edge e)
relation_kind
fur_stmt::query_relation (tree op1, tree op2)
{
- relation_oracle *oracle = m_query->oracle ();
- if (!oracle)
- return VREL_VARYING;
- return oracle->query_relation (m_stmt, op1, op2);
+ return m_query->oracle ().query_relation (m_stmt, op1, op2);
}
// Instantiate a stmt based fur_source with a GORI object.
@@ -192,10 +189,6 @@ fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q)
{
gcc_checking_assert (gori);
m_gori = gori;
- // Set relations if there is an oracle in the range_query.
- // This will enable registering of relationships as they are discovered.
- m_oracle = q->oracle ();
-
}
// Register a relation on a stmt if there is an oracle.
@@ -203,8 +196,7 @@ fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q)
void
fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2)
{
- if (m_oracle)
- m_oracle->register_stmt (s, k, op1, op2);
+ m_query->oracle ().register_relation (s, k, op1, op2);
}
// Register a relation on an edge if there is an oracle.
@@ -212,8 +204,7 @@ fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2)
void
fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2)
{
- if (m_oracle)
- m_oracle->register_edge (e, k, op1, op2);
+ m_query->oracle ().register_relation (e, k, op1, op2);
}
// This version of fur_source will pick a range up from a list of ranges
@@ -863,7 +854,7 @@ fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src)
tree single_arg = NULL_TREE;
bool seen_arg = false;
- relation_oracle *oracle = src.query()->oracle ();
+ relation_oracle *oracle = &(src.query()->oracle ());
// Start with an empty range, unioning in each argument's range.
r.set_undefined ();
for (x = 0; x < gimple_phi_num_args (phi); x++)
@@ -884,8 +875,7 @@ fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src)
// Likewise, if the incoming PHI argument is equivalent to this
// PHI definition, it provides no new info. Accumulate these ranges
// in case all arguments are equivalences.
- if (oracle
- && oracle->query_relation (e, arg, phi_def) == VREL_EQ)
+ if (oracle->query_relation (e, arg, phi_def) == VREL_EQ)
equiv_range.union_(arg_range);
else
r.union_ (arg_range);
@@ -1135,7 +1125,7 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
vrange &op2)
{
// No queries or already folded.
- if (!src.gori () || !src.query ()->oracle () || lhs_range.singleton_p ())
+ if (!src.gori () || lhs_range.singleton_p ())
return;
// Only care about AND and OR expressions.
@@ -138,8 +138,6 @@ public:
tree op2) override;
virtual void register_relation (edge e, relation_kind k, tree op1,
tree op2) override;
-protected:
- relation_oracle *m_oracle;
};
// This class uses ranges to fold a gimple statement producing a range for
@@ -44,7 +44,7 @@ path_range_query::path_range_query (gimple_ranger &ranger,
m_ranger (ranger),
m_resolve (resolve)
{
- m_oracle = new path_oracle (m_ranger.oracle ());
+ m_oracle = new path_oracle (&(m_ranger.oracle ()));
reset_path (path, dependencies);
}
@@ -54,7 +54,7 @@ path_range_query::path_range_query (gimple_ranger &ranger, bool resolve)
m_ranger (ranger),
m_resolve (resolve)
{
- m_oracle = new path_oracle (m_ranger.oracle ());
+ m_oracle = new path_oracle (&(m_ranger.oracle ()));
}
path_range_query::~path_range_query ()
@@ -563,7 +563,7 @@ path_range_query::compute_ranges (const bitmap_head *dependencies)
if (m_resolve)
{
path_oracle *p = get_path_oracle ();
- p->reset_path (m_ranger.oracle ());
+ p->reset_path (&(m_ranger.oracle ()));
}
if (DEBUG_SOLVER)
@@ -629,11 +629,6 @@ jt_fur_source::jt_fur_source (gimple *s,
gcc_checking_assert (!path.is_empty ());
m_entry = path[path.length () - 1];
-
- if (dom_info_available_p (CDI_DOMINATORS))
- m_oracle = query->oracle ();
- else
- m_oracle = NULL;
}
// Ignore statement and register relation on entry to path.
@@ -641,8 +636,7 @@ jt_fur_source::jt_fur_source (gimple *s,
void
jt_fur_source::register_relation (gimple *, relation_kind k, tree op1, tree op2)
{
- if (m_oracle)
- m_oracle->register_relation (m_entry, k, op1, op2);
+ m_query->oracle ().register_relation (m_entry, k, op1, op2);
}
// Ignore edge and register relation on entry to path.
@@ -650,20 +644,16 @@ jt_fur_source::register_relation (gimple *, relation_kind k, tree op1, tree op2)
void
jt_fur_source::register_relation (edge, relation_kind k, tree op1, tree op2)
{
- if (m_oracle)
- m_oracle->register_relation (m_entry, k, op1, op2);
+ m_query->oracle ().register_relation (m_entry, k, op1, op2);
}
relation_kind
jt_fur_source::query_relation (tree op1, tree op2)
{
- if (!m_oracle)
- return VREL_VARYING;
-
if (TREE_CODE (op1) != SSA_NAME || TREE_CODE (op2) != SSA_NAME)
return VREL_VARYING;
- return m_oracle->query_relation (m_entry, op1, op2);
+ return m_query->oracle().query_relation (m_entry, op1, op2);
}
// Return the range of STMT at the end of the path being analyzed.
@@ -43,8 +43,8 @@ gimple_ranger::gimple_ranger (bool use_imm_uses) :
tracer (""),
current_bb (NULL)
{
- // If the cache has a relation oracle, use it.
- m_oracle = m_cache.oracle ();
+ // Share the oracle from the cache.
+ m_oracle = &m_cache.oracle ();
if (dump_file && (param_ranger_debug & RANGER_DEBUG_TRACE))
tracer.enable_trace ();
m_stmt_list.create (0);
@@ -67,6 +67,7 @@ gimple_ranger::gimple_ranger (bool use_imm_uses) :
gimple_ranger::~gimple_ranger ()
{
+ // Restore the original oracle.
m_oracle = NULL;
m_stmt_list.release ();
}
@@ -178,15 +178,47 @@ range_query::dump (FILE *)
{
}
+// Default oracle for all range queries. This contains no storage and thus
+// can be used anywhere.
+relation_oracle default_relation_oracle;
+
+// Create dominance based range oracle for the current query if dom info is
+// available.
+
+void
+range_query::create_relation_oracle ()
+{
+ gcc_checking_assert (this != &global_ranges);
+ gcc_checking_assert (m_oracle == &default_relation_oracle);
+
+ if (!dom_info_available_p (CDI_DOMINATORS))
+ return;
+ m_oracle = new dom_oracle ();
+ gcc_checking_assert (m_oracle);
+}
+
+// Destroy any relation oracle that was created.
+
+void
+range_query::destroy_relation_oracle ()
+{
+ // m_oracle can be NULL if a derived range_query class took care of
+ // disposing its own oracle.
+ if (m_oracle && m_oracle != &default_relation_oracle)
+ {
+ delete m_oracle;
+ m_oracle = &default_relation_oracle;
+ }
+}
+
range_query::range_query ()
{
- m_oracle = NULL;
+ m_oracle = &default_relation_oracle;
}
range_query::~range_query ()
{
- if (m_oracle)
- destroy_relation_oracle ();
+ destroy_relation_oracle ();
}
// This routine will invoke the equivalent of range_of_expr on
@@ -75,12 +75,12 @@ public:
virtual bool range_on_entry (vrange &r, basic_block bb, tree expr);
virtual bool range_on_exit (vrange &r, basic_block bb, tree expr);
- inline relation_oracle *oracle () const { return m_oracle; }
+ inline class relation_oracle &oracle () const { return *m_oracle; }
+ void create_relation_oracle ();
+ void destroy_relation_oracle ();
virtual void dump (FILE *);
- void create_relation_oracle ();
- void destroy_relation_oracle ();
protected:
bool get_tree_range (vrange &v, tree expr, gimple *stmt,
basic_block bbentry = NULL, basic_block bbexit = NULL);
@@ -118,29 +118,4 @@ get_range_query (const struct function *fun)
// Query the global range of NAME in function F. Default to cfun.
extern void gimple_range_global (vrange &v, tree name,
struct function *f = cfun);
-
-// Create dominance based range oracle for the current query if dom info is
-// available.
-
-inline void
-range_query::create_relation_oracle ()
-{
- if (!dom_info_available_p (CDI_DOMINATORS))
- return;
- gcc_checking_assert (m_oracle == NULL);
- m_oracle = new dom_oracle ();
-}
-
-// Destroy any relation oracle that was created.
-
-inline void
-range_query::destroy_relation_oracle ()
-{
- if (m_oracle != NULL)
- {
- delete m_oracle;
- m_oracle = NULL;
- }
-}
-
#endif // GCC_QUERY_H
@@ -208,66 +208,6 @@ static const tree_code relation_to_code [VREL_LAST] = {
ERROR_MARK, ERROR_MARK, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EQ_EXPR,
NE_EXPR };
-// This routine validates that a relation can be applied to a specific set of
-// ranges. In particular, floating point x == x may not be true if the NaN bit
-// is set in the range. Symbolically the oracle will determine x == x,
-// but specific range instances may override this.
-// To verify, attempt to fold the relation using the supplied ranges.
-// One would expect [1,1] to be returned, anything else means there is something
-// in the range preventing the relation from applying.
-// If there is no mechanism to verify, assume the relation is acceptable.
-
-relation_kind
-relation_oracle::validate_relation (relation_kind rel, vrange &op1, vrange &op2)
-{
- // If there is no mapping to a tree code, leave the relation as is.
- tree_code code = relation_to_code [rel];
- if (code == ERROR_MARK)
- return rel;
-
- // Undefined ranges cannot be checked either.
- if (op1.undefined_p () || op2.undefined_p ())
- return rel;
-
- tree t1 = op1.type ();
- tree t2 = op2.type ();
-
- // If the range types are not compatible, no relation can exist.
- if (!range_compatible_p (t1, t2))
- return VREL_VARYING;
-
- // If there is no handler, leave the relation as is.
- range_op_handler handler (code);
- if (!handler)
- return rel;
-
- // If the relation cannot be folded for any reason, leave as is.
- Value_Range result (boolean_type_node);
- if (!handler.fold_range (result, boolean_type_node, op1, op2,
- relation_trio::op1_op2 (rel)))
- return rel;
-
- // The expression op1 REL op2 using REL should fold to [1,1].
- // Any other result means the relation is not verified to be true.
- if (result.varying_p () || result.zero_p ())
- return VREL_VARYING;
-
- return rel;
-}
-
-// If no range is available, create a varying range for each SSA name and
-// verify.
-
-relation_kind
-relation_oracle::validate_relation (relation_kind rel, tree ssa1, tree ssa2)
-{
- Value_Range op1, op2;
- op1.set_varying (TREE_TYPE (ssa1));
- op2.set_varying (TREE_TYPE (ssa2));
-
- return validate_relation (rel, op1, op2);
-}
-
// Given an equivalence set EQUIV, set all the bits in B that are still valid
// members of EQUIV in basic block BB.
@@ -1058,8 +998,8 @@ dom_oracle::~dom_oracle ()
// Register relation K between ssa_name OP1 and OP2 on STMT.
void
-relation_oracle::register_stmt (gimple *stmt, relation_kind k, tree op1,
- tree op2)
+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);
@@ -1106,7 +1046,7 @@ relation_oracle::register_stmt (gimple *stmt, relation_kind k, tree op1,
// Register relation K between ssa_name OP1 and OP2 on edge E.
void
-relation_oracle::register_edge (edge e, relation_kind k, tree op1, tree op2)
+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);
@@ -98,37 +98,37 @@ class relation_oracle
{
public:
virtual ~relation_oracle () { }
- // register a relation between 2 ssa names at a stmt.
- void register_stmt (gimple *, relation_kind, tree, tree);
- // register a relation between 2 ssa names on an edge.
- void register_edge (edge, relation_kind, tree, tree);
- // register a relation between 2 ssa names in a basic block.
- virtual void register_relation (basic_block, relation_kind, tree, tree) = 0;
+ // register a relation between 2 ssa names.
+ void register_relation (gimple *, relation_kind, tree, tree);
+ void register_relation (edge, relation_kind, tree, tree);
+ virtual void register_relation (basic_block, relation_kind, tree, tree) { }
+
// Query if there is any relation between SSA1 and SSA2.
- virtual relation_kind query_relation (basic_block, tree, tree) = 0;
relation_kind query_relation (gimple *s, tree ssa1, tree ssa2);
relation_kind query_relation (edge e, tree ssa1, tree ssa2);
+ virtual relation_kind query_relation (basic_block, tree, tree)
+ { return VREL_VARYING; }
- relation_kind validate_relation (relation_kind, tree, tree);
- relation_kind validate_relation (relation_kind, vrange &, vrange &);
-
- virtual void dump (FILE *, basic_block) const = 0;
- virtual void dump (FILE *) const = 0;
+ virtual void dump (FILE *, basic_block) const { }
+ virtual void dump (FILE *) const { }
void debug () const;
protected:
friend class equiv_relation_iterator;
// Return equivalency set for an SSA name in a basic block.
- virtual const_bitmap equiv_set (tree, basic_block) = 0;
+ virtual const_bitmap equiv_set (tree, basic_block) { return NULL; }
// Return partial equivalency record for an SSA name.
virtual const class pe_slice *partial_equiv_set (tree) { return NULL; }
void valid_equivs (bitmap b, const_bitmap equivs, basic_block bb);
// Query for a relation between two equivalency sets in a basic block.
virtual relation_kind query_relation (basic_block, const_bitmap,
- const_bitmap) = 0;
+ const_bitmap) { return VREL_VARYING; }
friend class path_oracle;
};
+// Instance with no storage used for default queries with no active oracle.
+extern relation_oracle default_relation_oracle;
+
// This class represents an equivalency set, and contains a link to the next
// one in the list to be searched.
@@ -162,11 +162,9 @@ 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)
@@ -175,6 +173,8 @@ public:
void dump (FILE *f) const override;
protected:
+ void add_partial_equiv (relation_kind, tree, tree);
+ const pe_slice *partial_equiv_set (tree name) final override;
inline bool has_equiv_p (unsigned v) { return bitmap_bit_p (m_equiv_set, v); }
bitmap_obstack m_bitmaps;
struct obstack m_chain_obstack;
--
2.41.0