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

Reply via email to