diff mbox

Improve x % y to x VRP optimization (PR tree-optimization/79408)

Message ID 20170207212302.GW1849@tucnak
State New
Headers show

Commit Message

Jakub Jelinek Feb. 7, 2017, 9:23 p.m. UTC
Hi!

While looking at the RTL problem when combiner optimizes away
(x & 0xfffe) % 0xffff into just (x & 0xfffe), I've looked at VRP
which optimizes that case well (-O2 only, the PR is -O1), but discovered
that it isn't generic enough, we actually don't need op1 to be constant
in this case, a range whose (positive) minimum satisfies it can be handled
the same.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk (or
shall I defer it for GCC8)?

2017-02-07  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/79408
	* tree-vrp.c (simplify_div_or_mod_using_ranges): If op1 is not
	constant, but SSA_NAME with a known integer range, use the minimum
	of that range instead of op1 to determine if modulo can be replaced
	with its first operand.

	* gcc.dg/tree-ssa/pr79408.c: New test.


	Jakub

Comments

Richard Biener Feb. 8, 2017, 8:41 a.m. UTC | #1
On Tue, 7 Feb 2017, Jakub Jelinek wrote:

> Hi!
> 
> While looking at the RTL problem when combiner optimizes away
> (x & 0xfffe) % 0xffff into just (x & 0xfffe), I've looked at VRP
> which optimizes that case well (-O2 only, the PR is -O1), but discovered
> that it isn't generic enough, we actually don't need op1 to be constant
> in this case, a range whose (positive) minimum satisfies it can be handled
> the same.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk (or
> shall I defer it for GCC8)?

Ok for trunk if you adjust the function comment accordingly.

Thanks,
Richard.

> 2017-02-07  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/79408
> 	* tree-vrp.c (simplify_div_or_mod_using_ranges): If op1 is not
> 	constant, but SSA_NAME with a known integer range, use the minimum
> 	of that range instead of op1 to determine if modulo can be replaced
> 	with its first operand.
> 
> 	* gcc.dg/tree-ssa/pr79408.c: New test.
> 
> --- gcc/tree-vrp.c.jj	2017-01-30 19:10:50.000000000 +0100
> +++ gcc/tree-vrp.c	2017-02-07 12:33:32.721482609 +0100
> @@ -9241,17 +9241,25 @@ simplify_div_or_mod_using_ranges (gimple
>    tree val = NULL;
>    tree op0 = gimple_assign_rhs1 (stmt);
>    tree op1 = gimple_assign_rhs2 (stmt);
> +  tree op1min = op1;
>    value_range *vr = get_value_range (op0);
>  
>    if (rhs_code == TRUNC_MOD_EXPR
> -      && TREE_CODE (op1) == INTEGER_CST
> -      && tree_int_cst_sgn (op1) == 1
> +      && TREE_CODE (op1) == SSA_NAME)
> +    {
> +      value_range *vr1 = get_value_range (op1);
> +      if (range_int_cst_p (vr1))
> +	op1min = vr1->min;
> +    }
> +  if (rhs_code == TRUNC_MOD_EXPR
> +      && TREE_CODE (op1min) == INTEGER_CST
> +      && tree_int_cst_sgn (op1min) == 1
>        && range_int_cst_p (vr)
> -      && tree_int_cst_lt (vr->max, op1))
> +      && tree_int_cst_lt (vr->max, op1min))
>      {
>        if (TYPE_UNSIGNED (TREE_TYPE (op0))
>  	  || tree_int_cst_sgn (vr->min) >= 0
> -	  || tree_int_cst_lt (fold_unary (NEGATE_EXPR, TREE_TYPE (op1), op1),
> -			      vr->min))
> +	  || tree_int_cst_lt (fold_unary (NEGATE_EXPR, TREE_TYPE (op1min),
> +					  op1min), vr->min))
>  	{
>  	  /* If op0 already has the range op0 % op1 has,
> --- gcc/testsuite/gcc.dg/tree-ssa/pr79408.c.jj	2017-02-07 16:30:42.439774777 +0100
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr79408.c	2017-02-07 16:32:37.653282317 +0100
> @@ -0,0 +1,40 @@
> +/* PR tree-optimization/79408 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +void link_error (void);
> +
> +void
> +foo (unsigned int x, unsigned int y)
> +{
> +  if (x > 7312)
> +    return;
> +  if (y <= 7312)
> +    return;
> +  if (x % y != x)
> +    link_error ();
> +}
> +
> +void
> +bar (int x, int y)
> +{
> +  if (x > 7312 || x < 0)
> +    return;
> +  if (y <= 7312)
> +    return;
> +  if (x % y != x)
> +    link_error ();
> +}
> +
> +void
> +baz (int x, int y)
> +{
> +  if (x > 7312 || x < -7312)
> +    return;
> +  if (y <= 7312)
> +    return;
> +  if (x % y != x)
> +    link_error ();
> +}
> +
> +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */
> 
> 	Jakub
> 
>
Bernhard Reutner-Fischer Feb. 10, 2017, 7:36 a.m. UTC | #2
On 8 February 2017 09:41:47 CET, Richard Biener <rguenther@suse.de> wrote:
>On Tue, 7 Feb 2017, Jakub Jelinek wrote:

>> +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} }
>*/

scan-tree-dump-not would have been more expressive, FWIW.
Marc Glisse Feb. 12, 2017, 5:44 a.m. UTC | #3
On Tue, 7 Feb 2017, Jakub Jelinek wrote:

> 	* tree-vrp.c (simplify_div_or_mod_using_ranges): If op1 is not
> 	constant, but SSA_NAME with a known integer range, use the minimum
> 	of that range instead of op1 to determine if modulo can be replaced
> 	with its first operand.

Would it make sense to use something like the operand_less_p helper so we 
would also handle an INTEGER_CST lhs?

unsigned f(unsigned x){
   if(x<42)return 18;
   return 33%x;
}
Marc Glisse Feb. 12, 2017, 6:27 a.m. UTC | #4
On Sun, 12 Feb 2017, Marc Glisse wrote:

> On Tue, 7 Feb 2017, Jakub Jelinek wrote:
>
>> 	* tree-vrp.c (simplify_div_or_mod_using_ranges): If op1 is not
>> 	constant, but SSA_NAME with a known integer range, use the minimum
>> 	of that range instead of op1 to determine if modulo can be replaced
>> 	with its first operand.
>
> Would it make sense to use something like the operand_less_p helper so we 
> would also handle an INTEGER_CST lhs?

Oops, operand_less_p is just a helper for compare_values_warnv and even 
that one doesn't seem to use ranges, so there may not already be a nice 
function we can call (?). The idea remains that reusing such code would 
help handle more cases (it may even handle a few symbolic cases).

> unsigned f(unsigned x){
>  if(x<42)return 18;
>  return 33%x;
> }
Richard Biener Feb. 13, 2017, 8:59 a.m. UTC | #5
On Sun, 12 Feb 2017, Marc Glisse wrote:

> On Sun, 12 Feb 2017, Marc Glisse wrote:
> 
> > On Tue, 7 Feb 2017, Jakub Jelinek wrote:
> > 
> > > 	* tree-vrp.c (simplify_div_or_mod_using_ranges): If op1 is not
> > > 	constant, but SSA_NAME with a known integer range, use the minimum
> > > 	of that range instead of op1 to determine if modulo can be replaced
> > > 	with its first operand.
> > 
> > Would it make sense to use something like the operand_less_p helper so we
> > would also handle an INTEGER_CST lhs?
> 
> Oops, operand_less_p is just a helper for compare_values_warnv and even that
> one doesn't seem to use ranges, so there may not already be a nice function we
> can call (?). The idea remains that reusing such code would help handle more
> cases (it may even handle a few symbolic cases).

Yeah, we only have the compare_range_with_value / compare_ranges functions
and those require you to "expand" the value you have a range for first.

Richard.

> > unsigned f(unsigned x){
> >  if(x<42)return 18;
> >  return 33%x;
> > }
> 
>
diff mbox

Patch

--- gcc/tree-vrp.c.jj	2017-01-30 19:10:50.000000000 +0100
+++ gcc/tree-vrp.c	2017-02-07 12:33:32.721482609 +0100
@@ -9241,17 +9241,25 @@  simplify_div_or_mod_using_ranges (gimple
   tree val = NULL;
   tree op0 = gimple_assign_rhs1 (stmt);
   tree op1 = gimple_assign_rhs2 (stmt);
+  tree op1min = op1;
   value_range *vr = get_value_range (op0);
 
   if (rhs_code == TRUNC_MOD_EXPR
-      && TREE_CODE (op1) == INTEGER_CST
-      && tree_int_cst_sgn (op1) == 1
+      && TREE_CODE (op1) == SSA_NAME)
+    {
+      value_range *vr1 = get_value_range (op1);
+      if (range_int_cst_p (vr1))
+	op1min = vr1->min;
+    }
+  if (rhs_code == TRUNC_MOD_EXPR
+      && TREE_CODE (op1min) == INTEGER_CST
+      && tree_int_cst_sgn (op1min) == 1
       && range_int_cst_p (vr)
-      && tree_int_cst_lt (vr->max, op1))
+      && tree_int_cst_lt (vr->max, op1min))
     {
       if (TYPE_UNSIGNED (TREE_TYPE (op0))
 	  || tree_int_cst_sgn (vr->min) >= 0
-	  || tree_int_cst_lt (fold_unary (NEGATE_EXPR, TREE_TYPE (op1), op1),
-			      vr->min))
+	  || tree_int_cst_lt (fold_unary (NEGATE_EXPR, TREE_TYPE (op1min),
+					  op1min), vr->min))
 	{
 	  /* If op0 already has the range op0 % op1 has,
--- gcc/testsuite/gcc.dg/tree-ssa/pr79408.c.jj	2017-02-07 16:30:42.439774777 +0100
+++ gcc/testsuite/gcc.dg/tree-ssa/pr79408.c	2017-02-07 16:32:37.653282317 +0100
@@ -0,0 +1,40 @@ 
+/* PR tree-optimization/79408 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+void link_error (void);
+
+void
+foo (unsigned int x, unsigned int y)
+{
+  if (x > 7312)
+    return;
+  if (y <= 7312)
+    return;
+  if (x % y != x)
+    link_error ();
+}
+
+void
+bar (int x, int y)
+{
+  if (x > 7312 || x < 0)
+    return;
+  if (y <= 7312)
+    return;
+  if (x % y != x)
+    link_error ();
+}
+
+void
+baz (int x, int y)
+{
+  if (x > 7312 || x < -7312)
+    return;
+  if (y <= 7312)
+    return;
+  if (x % y != x)
+    link_error ();
+}
+
+/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */