From 985581b05f32b62df15b60833a8a57544dbbd739 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Thu, 2 May 2024 12:23:18 -0400
Subject: [PATCH 06/12] 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.
---
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(-)
@@ -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.
@@ -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);
@@ -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.
@@ -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
--
2.41.0