]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add inferred ranges for range-ops based statements.
authorAndrew MacLeod <amacleod@redhat.com>
Thu, 2 May 2024 16:23:18 +0000 (12:23 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Thu, 23 May 2024 20:48:44 +0000 (16:48 -0400)
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
gcc/gimple-range-fold.h
gcc/gimple-range-infer.cc
gcc/gimple-range-infer.h

index 357a1beabd1acba7b7f4cccd927824160f207d17..9e9c5960972a802f3e100c7045131b46a4979f3d 100644 (file)
@@ -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.
index 1925fb899e3e2dff6a2f335e462c0b507fd7fc4f..d974b0192c844c09ad4e45cd89492cd3bc9a2fdd 100644 (file)
@@ -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);
 
index 757a2013c58a4088df52fcd95bcf4eadbcfb6daa..2571a4d127f18eddd39cffdaa217ca8027145f4a 100644 (file)
@@ -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.
index fd5b2ad8ddeb1ed851122d13a4a6e8e92750304c..d2c151c4b9d0a79a1e61324247f156a855f0ccb3 100644 (file)
@@ -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