diff mbox

Optimize (x % 5) % 5 in VRP (PR tree-optimization/64454)

Message ID 20150112202818.GU1405@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Jan. 12, 2015, 8:28 p.m. UTC
Hi!

This patch optimizes away TRUNC_MOD_EXPR by constant second argument
(if not 0 and not type's minimum) if the range of the first argument
is already known to be [-op1 + 1, op1 - 1] or its subset.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2015-01-12  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/64454
	* tree-vrp.c (simplify_div_or_mod_using_ranges): Optimize
	op0 % op1 into op0 if op0 is in range [-op1 + 1, op1 - 1]
	for signed or [0, op1 - 1] for unsigned modulo.
	(simplify_stmt_using_ranges): Call simplify_div_or_mod_using_ranges
	even if op1 does not satisfy integer_pow2p.

	* gcc.dg/pr64454.c: New test.


	Jakub

Comments

Jeff Law Jan. 12, 2015, 8:43 p.m. UTC | #1
On 01/12/15 13:28, Jakub Jelinek wrote:
> Hi!
>
> This patch optimizes away TRUNC_MOD_EXPR by constant second argument
> (if not 0 and not type's minimum) if the range of the first argument
> is already known to be [-op1 + 1, op1 - 1] or its subset.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2015-01-12  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR tree-optimization/64454
> 	* tree-vrp.c (simplify_div_or_mod_using_ranges): Optimize
> 	op0 % op1 into op0 if op0 is in range [-op1 + 1, op1 - 1]
> 	for signed or [0, op1 - 1] for unsigned modulo.
> 	(simplify_stmt_using_ranges): Call simplify_div_or_mod_using_ranges
> 	even if op1 does not satisfy integer_pow2p.
>
> 	* gcc.dg/pr64454.c: New test.
OK.
jeff
diff mbox

Patch

--- gcc/tree-vrp.c.jj	2015-01-12 11:21:50.000000000 +0100
+++ gcc/tree-vrp.c	2015-01-12 18:45:23.349335792 +0100
@@ -8998,7 +8998,11 @@  simplify_truth_ops_using_ranges (gimple_
 
 /* Simplify a division or modulo operator to a right shift or
    bitwise and if the first operand is unsigned or is greater
-   than zero and the second operand is an exact power of two.  */
+   than zero and the second operand is an exact power of two.
+   For TRUNC_MOD_EXPR op0 % op1 with constant op1, optimize it
+   into just op0 if op0's range is known to be a subset of
+   [-op1 + 1, op1 - 1] for signed and [0, op1 - 1] for unsigned
+   modulo.  */
 
 static bool
 simplify_div_or_mod_using_ranges (gimple stmt)
@@ -9007,7 +9011,30 @@  simplify_div_or_mod_using_ranges (gimple
   tree val = NULL;
   tree op0 = gimple_assign_rhs1 (stmt);
   tree op1 = gimple_assign_rhs2 (stmt);
-  value_range_t *vr = get_value_range (gimple_assign_rhs1 (stmt));
+  value_range_t *vr = get_value_range (op0);
+
+  if (rhs_code == TRUNC_MOD_EXPR
+      && TREE_CODE (op1) == INTEGER_CST
+      && tree_int_cst_sgn (op1) == 1
+      && range_int_cst_p (vr)
+      && tree_int_cst_lt (vr->max, op1))
+    {
+      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))
+	{
+	  /* If op0 already has the range op0 % op1 has,
+	     then TRUNC_MOD_EXPR won't change anything.  */
+	  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+	  gimple_assign_set_rhs_from_tree (&gsi, op0);
+	  update_stmt (stmt);
+	  return true;
+	}
+    }
+
+  if (!integer_pow2p (op1))
+    return false;
 
   if (TYPE_UNSIGNED (TREE_TYPE (op0)))
     {
@@ -9880,11 +9907,14 @@  simplify_stmt_using_ranges (gimple_stmt_
 
       /* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
 	 and BIT_AND_EXPR respectively if the first operand is greater
-	 than zero and the second operand is an exact power of two.  */
+	 than zero and the second operand is an exact power of two.
+	 Also optimize TRUNC_MOD_EXPR away if the second operand is
+	 constant and the first operand already has the right value
+	 range.  */
 	case TRUNC_DIV_EXPR:
 	case TRUNC_MOD_EXPR:
-	  if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
-	      && integer_pow2p (gimple_assign_rhs2 (stmt)))
+	  if (TREE_CODE (rhs1) == SSA_NAME
+	      && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
 	    return simplify_div_or_mod_using_ranges (stmt);
 	  break;
 
--- gcc/testsuite/gcc.dg/pr64454.c.jj	2015-01-12 18:49:32.270004660 +0100
+++ gcc/testsuite/gcc.dg/pr64454.c	2015-01-12 18:50:43.964757197 +0100
@@ -0,0 +1,43 @@ 
+/* PR tree-optimization/64454 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+unsigned
+f1 (unsigned x)
+{
+  return (x % 5) % 5;
+}
+
+int
+f2 (int x)
+{
+  return (x % 5) % 5;
+}
+
+int
+f3 (int x)
+{
+  return (x % -5) % -5;
+}
+
+unsigned
+f4 (unsigned x)
+{
+  return (x % 5) % 6;
+}
+
+int
+f5 (int x)
+{
+  return (x % 5) % 6;
+}
+
+int
+f6 (int x)
+{
+  return (x % -5) % -6;
+}
+
+/* { dg-final { scan-tree-dump-times "% 5" 6 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "% 6" 0 "vrp1" } } */
+/* { dg-final { cleanup-tree-dump "vrp1" } } */