https://gcc.gnu.org/g:efc4255d4393cba3d2232a7152799e1b161c3062
commit r15-802-gefc4255d4393cba3d2232a7152799e1b161c3062 Author: Andrew MacLeod <amacl...@redhat.com> Date: Thu May 2 12:23:18 2024 -0400 Add inferred ranges for range-ops based statements. Gimple_range_fold contains some shorthand fold_range routines for easy user consumption of that range-ops interface, but there is no equivalent routines for op1_range and op2_range. This patch provides basic versions. Any range-op entry which has an op1_range or op2_range implemented can potentially also provide inferred ranges. This is a step towards PR 113879. Default is currently OFF for performance reasons as it dramtically increases the number of inferred ranges. PR tree-optimization/113879 * gimple-range-fold.cc (op1_range): New. (op2_range): New. * gimple-range-fold.h (op1_range): New prototypes. (op2_range): New prototypes. * gimple-range-infer.cc (gimple_infer_range::add_range): Do not add an inferred range if it is VARYING. (gimple_infer_range::gimple_infer_range): Add inferred ranges for any range-op statements if requested. * gimple-range-infer.h (gimple_infer_range): Add parameter. Diff: --- gcc/gimple-range-fold.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++++ gcc/gimple-range-fold.h | 7 +++++ gcc/gimple-range-infer.cc | 41 ++++++++++++++++++++++++++- gcc/gimple-range-infer.h | 2 +- 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 357a1beabd1..9e9c5960972 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -328,6 +328,77 @@ fold_range (vrange &r, gimple *s, edge on_edge, range_query *q) return f.fold_stmt (r, s, src); } +// Calculate op1 on statetemt S with LHS into range R using range query Q +// to resolve any other operands. + +bool +op1_range (vrange &r, gimple *s, const vrange &lhs, range_query *q) +{ + gimple_range_op_handler handler (s); + if (!handler) + return false; + + fur_stmt src (s, q); + + tree op2_expr = handler.operand2 (); + if (!op2_expr) + return handler.calc_op1 (r, lhs); + + Value_Range op2 (TREE_TYPE (op2_expr)); + if (!src.get_operand (op2, op2_expr)) + return false; + + return handler.calc_op1 (r, lhs, op2); +} + +// Calculate op1 on statetemt S into range R using range query Q. +// LHS is set to VARYING in this case. + +bool +op1_range (vrange &r, gimple *s, range_query *q) +{ + tree lhs_type = gimple_range_type (s); + if (!lhs_type) + return false; + Value_Range lhs_range; + lhs_range.set_varying (lhs_type); + return op1_range (r, s, lhs_range, q); +} + +// Calculate op2 on statetemt S with LHS into range R using range query Q +// to resolve any other operands. + +bool +op2_range (vrange &r, gimple *s, const vrange &lhs, range_query *q) +{ + + gimple_range_op_handler handler (s); + if (!handler) + return false; + + fur_stmt src (s, q); + + Value_Range op1 (TREE_TYPE (handler.operand1 ())); + if (!src.get_operand (op1, handler.operand1 ())) + return false; + + return handler.calc_op2 (r, lhs, op1); +} + +// Calculate op2 on statetemt S into range R using range query Q. +// LHS is set to VARYING in this case. + +bool +op2_range (vrange &r, gimple *s, range_query *q) +{ + tree lhs_type = gimple_range_type (s); + if (!lhs_type) + return false; + Value_Range lhs_range; + lhs_range.set_varying (lhs_type); + return op2_range (r, s, lhs_range, q); +} + // Provide a fur_source which can be used to determine any relations on // a statement. It manages the callback from fold_using_ranges to determine // a relation_trio for a statement. diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index 1925fb899e3..d974b0192c8 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -43,6 +43,13 @@ bool fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2, bool fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector, range_query *q = NULL); +// Calculate op1 on stmt S. +bool op1_range (vrange &, gimple *s, range_query *q = NULL); +bool op1_range (vrange &, gimple *s, const vrange &lhs, range_query *q = NULL); +// Calculate op2 on stmt S. +bool op2_range (vrange &, gimple *s, range_query *q = NULL); +bool op2_range (vrange &, gimple *s, const vrange &lhs, range_query *q = NULL); + // This routine will return a relation trio for stmt S. relation_trio fold_relations (gimple *s, range_query *q = NULL); diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc index 757a2013c58..2571a4d127f 100644 --- a/gcc/gimple-range-infer.cc +++ b/gcc/gimple-range-infer.cc @@ -129,6 +129,9 @@ gimple_infer_range::check_assume_func (gcall *call) void gimple_infer_range::add_range (tree name, vrange &range) { + // Do not add an inferred range if it is VARYING. + if (range.varying_p ()) + return; m_names[num_args] = name; m_ranges[num_args] = range; if (num_args < size_limit - 1) @@ -149,8 +152,12 @@ gimple_infer_range::add_nonzero (tree name) // Process S for range inference and fill in the summary list. // This is the routine where new inferred ranges should be added. +// If USE_RANGEOPS is true, invoke range-ops on stmts with a single +// ssa-name aa constant to reflect an inferred range. ie +// x_2 = y_3 + 1 will provide an inferred range for y_3 of [-INF, +INF - 1]. +// This defaults to FALSE as it can be expensive., -gimple_infer_range::gimple_infer_range (gimple *s) +gimple_infer_range::gimple_infer_range (gimple *s, bool use_rangeops) { num_args = 0; @@ -190,6 +197,38 @@ gimple_infer_range::gimple_infer_range (gimple *s) walk_stmt_load_store_ops (s, (void *)this, non_null_loadstore, non_null_loadstore); + // Gated by flag. + if (!use_rangeops) + return; + + // Check if there are any inferred ranges from range-ops. + gimple_range_op_handler handler (s); + if (!handler) + return; + + // Only proceed if ONE operand is an SSA_NAME, This may provide an + // inferred range for 'y + 3' , but will bypass expressions like + // 'y + z' as it depends on symbolic values. + tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); + tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); + if ((ssa1 != NULL) == (ssa2 != NULL)) + return; + + // The other operand should be a constant, so just use the global range + // query to pick up any other values. + if (ssa1) + { + Value_Range op1 (TREE_TYPE (ssa1)); + if (op1_range (op1, s, get_global_range_query ()) && !op1.varying_p ()) + add_range (ssa1, op1); + } + else + { + gcc_checking_assert (ssa2); + Value_Range op2 (TREE_TYPE (ssa2)); + if (op2_range (op2, s, get_global_range_query ()) && !op2.varying_p ()) + add_range (ssa2, op2); + } } // Create an single inferred range for NAMe using range R. diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h index fd5b2ad8dde..d2c151c4b9d 100644 --- a/gcc/gimple-range-infer.h +++ b/gcc/gimple-range-infer.h @@ -31,7 +31,7 @@ along with GCC; see the file COPYING3. If not see class gimple_infer_range { public: - gimple_infer_range (gimple *s); + gimple_infer_range (gimple *s, bool use_rangeops = false); gimple_infer_range (tree name, vrange &r); inline unsigned num () const { return num_args; } inline tree name (unsigned index) const