diff mbox series

recognize implied ranges for modulo.

Message ID e6e36e5c-0f4f-5edf-a4f1-2dea74bfedd7@redhat.com
State New
Headers show
Series recognize implied ranges for modulo. | expand

Commit Message

Andrew MacLeod Nov. 17, 2020, 10:01 p.m. UTC
PR 91029 observes when

  a % b > 0 && b >= 0,

then a has an implied range of  a >=0.  likewise

a % b < 0 implies a range of a <= 0.

This patch is a good example of how range-ops can be leveraged to solve 
problems. It simply implements operator_trunc_mod::op1_range()  to solve 
for 'A' when the LHS and 'b' are known to be within the specified 
ranges.    I also added a a test case to show folding of conditions 
based on that.

Bootstrapped on x86_64-pc-linux-gnu, no regressions.  pushed.

Andrew

Comments

Aldy Hernandez Nov. 18, 2020, 8:35 a.m. UTC | #1
On 11/17/20 11:01 PM, Andrew MacLeod wrote:
> PR 91029 observes when
> 
>   a % b > 0 && b >= 0,
> 
> then a has an implied range of  a >=0.  likewise

Shouldn't that be && b > 0?  b == 0 is undefined.

> 
> a % b < 0 implies a range of a <= 0.
> 
> This patch is a good example of how range-ops can be leveraged to solve 
> problems. It simply implements operator_trunc_mod::op1_range()  to solve 
> for 'A' when the LHS and 'b' are known to be within the specified 
> ranges.    I also added a a test case to show folding of conditions 
> based on that.
> 
> Bootstrapped on x86_64-pc-linux-gnu, no regressions.  pushed.
> 
> Andrew


> diff --git a/gcc/range-op.cc b/gcc/range-op.cc
> index d0adc95527a..f37796cac70 100644
> --- a/gcc/range-op.cc
> +++ b/gcc/range-op.cc
> @@ -2634,6 +2634,9 @@ public:
>  		        const wide_int &lh_ub,
>  		        const wide_int &rh_lb,
>  		        const wide_int &rh_ub) const;
> +  virtual bool op1_range (irange &r, tree type,
> +			  const irange &lhs,
> +			  const irange &op2) const;
>  } op_trunc_mod;
>  
>  void
> @@ -2680,6 +2683,31 @@ operator_trunc_mod::wi_fold (irange &r, tree type,
>    value_range_with_overflow (r, type, new_lb, new_ub);
>  }
>  
> +bool
> +operator_trunc_mod::op1_range (irange &r, tree type,
> +			       const irange &lhs,
> +			       const irange &op2) const
> +{
> +  // PR 91029.  Check for signed truncation with op2 >= 0.
> +  if (TYPE_SIGN (type) == SIGNED && wi::ge_p (op2.lower_bound (), 0, SIGNED))
> +    {
> +      unsigned prec = TYPE_PRECISION (type);
> +      // if a & b >=0 , then a >= 0.

Shouldn't comment be %, not & ??.

> +      if (wi::ge_p (lhs.lower_bound (), 0, SIGNED))
> +	{
> +	  r = value_range (type, wi::zero (prec), wi::max_value (prec, SIGNED));
> +	  return true;
> +	}
> +      // if a & b < 0 , then a <= 0.

Similarly here.

> +      if (wi::lt_p (lhs.upper_bound (), 0, SIGNED))
> +	{
> +	  r = value_range (type, wi::min_value (prec, SIGNED), wi::zero (prec));
> +	  return true;
> +	}
> +    }
> +  return false;
> +}
> +
>  

Thanks for doing this BTW.
Aldy
Andrew MacLeod Nov. 18, 2020, 2:22 p.m. UTC | #2
On 11/18/20 3:35 AM, Aldy Hernandez wrote:
>
>
> On 11/17/20 11:01 PM, Andrew MacLeod wrote:
>> PR 91029 observes when
>>
>>   a % b > 0 && b >= 0,
>>
>> then a has an implied range of  a >=0.  likewise
>
> Shouldn't that be && b > 0?  b == 0 is undefined.
>
>
If you were folding, sure, but  I think its OK for equation solving.. 
whats important is that b is not negative.
  I can easily imagine having a positive LHS and an unknown unsigned 
value for b..   we could still conclude that 'a' is positive even though 
0 is in the "possible ranges" for 'b'

Andrew
diff mbox series

Patch

commit 1e27e7a582a9b86bcf86f5c103cd947672746e97
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue Nov 17 14:47:58 2020 -0500

    recognize implied ranges for modulo.
    
    implement op1_range for modulo with implied positive and negative ranges.
    
            gcc/
            PR tree-optimization/91029
            * range-op.cc (operator_trunc_mod::op1_range): New.
            gcc/testsuite/
            * gcc.dg/pr91029.c: New.

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index d0adc95527a..f37796cac70 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2634,6 +2634,9 @@  public:
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
 		        const wide_int &rh_ub) const;
+  virtual bool op1_range (irange &r, tree type,
+			  const irange &lhs,
+			  const irange &op2) const;
 } op_trunc_mod;
 
 void
@@ -2680,6 +2683,31 @@  operator_trunc_mod::wi_fold (irange &r, tree type,
   value_range_with_overflow (r, type, new_lb, new_ub);
 }
 
+bool
+operator_trunc_mod::op1_range (irange &r, tree type,
+			       const irange &lhs,
+			       const irange &op2) const
+{
+  // PR 91029.  Check for signed truncation with op2 >= 0.
+  if (TYPE_SIGN (type) == SIGNED && wi::ge_p (op2.lower_bound (), 0, SIGNED))
+    {
+      unsigned prec = TYPE_PRECISION (type);
+      // if a & b >=0 , then a >= 0.
+      if (wi::ge_p (lhs.lower_bound (), 0, SIGNED))
+	{
+	  r = value_range (type, wi::zero (prec), wi::max_value (prec, SIGNED));
+	  return true;
+	}
+      // if a & b < 0 , then a <= 0.
+      if (wi::lt_p (lhs.upper_bound (), 0, SIGNED))
+	{
+	  r = value_range (type, wi::min_value (prec, SIGNED), wi::zero (prec));
+	  return true;
+	}
+    }
+  return false;
+}
+
 
 class operator_logical_not : public range_operator
 {
diff --git a/gcc/testsuite/gcc.dg/pr91029.c b/gcc/testsuite/gcc.dg/pr91029.c
new file mode 100644
index 00000000000..8a4134c5d96
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91029.c
@@ -0,0 +1,47 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void kill (void);
+int xx;
+
+void f1 (int i)
+{
+  if ((i % 7) == 3)
+    {
+      xx = (i < 0);
+      if (xx)
+        kill ();
+    }
+}
+
+void f2 (int i)
+{
+  if ((i % 7) >= 0)
+    {
+      xx = (i < 0);
+      if (xx)
+        kill ();
+    }
+}
+
+void f3 (int i)
+{
+  if ((i % 7) == -3)
+    {
+      xx = (i > 0);
+      if (xx)
+        kill ();
+    }
+}
+
+void f4 (int i)
+{
+  if ((i % 7) < 0)
+    {
+      xx = (i > 0);
+      if (xx)
+        kill ();
+    }
+}
+
+/* { dg-final { scan-tree-dump-not "kill" "evrp" } }  */