{
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
// 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");
}
}
}
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.
{
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.
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.
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
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++)
// 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);
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.
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
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);
}
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 ()
if (m_resolve)
{
path_oracle *p = get_path_oracle ();
- p->reset_path (m_ranger.oracle ());
+ p->reset_path (&(m_ranger.oracle ()));
}
if (DEBUG_SOLVER)
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.
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.
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.
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);
gimple_ranger::~gimple_ranger ()
{
+ // Restore the original oracle.
m_oracle = NULL;
m_stmt_list.release ();
}
{
}
+// 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
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);
// 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
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.
// 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);
// 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);
{
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.
~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)
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;