diff mbox series

[COMMITTED,06/12] tree-optimization/113879 - Add inferred ranges for range-ops based statements.

Message ID 1531cb9e-a373-4186-8d4a-eb190ad7616e@redhat.com
State New
Headers show
Series [COMMITTED,01/12] - Move all relation queries into relation_oracle. | expand

Commit Message

Andrew MacLeod May 23, 2024, 8:53 p.m. UTC
gimple_range_fold contains some shorthand fold_range routines for easy 
user consumption of the range-ops interface, but there is no equivalent
routines for op1_range and op2_range.  This patch provides basic versions.

I have started range-op documentation, but its very early days so not 
that useful yet: https://gcc.gnu.org/wiki/AndrewMacLeod/RangeOperator

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 
dramatically increases the number of inferred ranges past where the 
current engine is comfortable with, but the functionality will now be 
there to move towards fixing the PR.  It might be appropriate for -O3, 
but I'll hold of for the moment.

Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.
diff mbox series

Patch

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(-)

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
-- 
2.41.0