From 2f80eb1feb3f92c7e9e57d4726ec52ca7d27ce92 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod 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(-) diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index cf17a6af9db..020069fd635 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -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"); } } } diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 41b6d350c40..eeffdce0b97 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -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. diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index c7c599bfc93..1925fb899e3 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -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 diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index ef3db10470e..cf7e0409098 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -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. diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 22e8add5de1..24ffd63c89b 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -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 (); } diff --git a/gcc/value-query.cc b/gcc/value-query.cc index b275a43b679..03ce574bcb5 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -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 diff --git a/gcc/value-query.h b/gcc/value-query.h index 9df89905ace..ed355bedfa8 100644 --- a/gcc/value-query.h +++ b/gcc/value-query.h @@ -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 diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc index d1081b3b3f5..fac15613945 100644 --- a/gcc/value-relation.cc +++ b/gcc/value-relation.cc @@ -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); diff --git a/gcc/value-relation.h b/gcc/value-relation.h index 5adf736cf41..528f00aecbb 100644 --- a/gcc/value-relation.h +++ b/gcc/value-relation.h @@ -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