Hello,

this kind of simplification is already handled by fold_comparison, but the code is common with TRUNC_DIV_EXPR, which yields suboptimal code. In particular, for an unsigned number, X/8==0 means x<=7, while X/[ex]8==0 can be turned into X==0.

When we have an explicit division by 0, there is a better optimisation possible (insert __builtin_unreachable() or __builtin_trap() after that statement, as in find_explicit_erroneous_behavior), so I don't touch it.

For the overflow inequality case, it would have been a bit clearer to generate
  (cmp { build_zero_cst (TREE_TYPE (@0)); } @2)
and let that be constant folded instead of having that ugly and error-prone test in constant_boolean_node, but I saved one tree ;-)

Bootstrap+regtest on powerpc64le-unknown-linux-gnu, all the regressions are in the libitm part of the testsuite, they should be fixed by https://gcc.gnu.org/ml/gcc-patches/2016-10/msg02220.html , I'll rerun the testsuite when that patch is in.

2016-11-07  Marc Glisse  <marc.gli...@inria.fr>

gcc/
        * fold-const.c (fold_comparison): Ignore EXACT_DIV_EXPR.
        * match.pd (A /[ex] B CMP C): New simplifications.

gcc/testsuite/
        * gcc.dg/tree-ssa/cmpexactdiv.c: New file.

--
Marc Glisse
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 241840)
+++ gcc/fold-const.c	(working copy)
@@ -8740,22 +8740,21 @@ fold_comparison (location_t loc, enum tr
 		  SET_EXPR_LOCATION (tem, loc);
 		  return tem;
 		}
 	      return fold_build2_loc (loc, code, type, cval1, cval2);
 	    }
 	}
     }
 
   /* We can fold X/C1 op C2 where C1 and C2 are integer constants
      into a single range test.  */
-  if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
-       || TREE_CODE (arg0) == EXACT_DIV_EXPR)
+  if (TREE_CODE (arg0) == TRUNC_DIV_EXPR
       && TREE_CODE (arg1) == INTEGER_CST
       && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
       && !integer_zerop (TREE_OPERAND (arg0, 1))
       && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
       && !TREE_OVERFLOW (arg1))
     {
       tem = fold_div_compare (loc, code, type, arg0, arg1);
       if (tem != NULL_TREE)
 	return tem;
     }
Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 241840)
+++ gcc/match.pd	(working copy)
@@ -2314,20 +2314,50 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 	   (ne @0 { build_real (TREE_TYPE (@0), c2); }))))
 	/* sqrt(x) < c is the same as x < c*c, if we ignore NaNs.  */
 	(if (! HONOR_NANS (@0))
 	 (cmp @0 { build_real (TREE_TYPE (@0), c2); })
 	 /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
 	 (if (GENERIC)
 	  (truth_andif
 	   (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
 	   (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))))))))))
 
+/* Fold A /[ex] B CMP C to A CMP B * C.  */
+(for cmp (eq ne)
+ (simplify
+  (cmp (exact_div @0 @1) INTEGER_CST@2)
+  (if (!integer_zerop (@1))
+   (if (wi::eq_p (@2, 0))
+    (cmp @0 @2)
+    (if (TREE_CODE (@1) == INTEGER_CST)
+     (with
+      {
+	bool ovf;
+	wide_int prod = wi::mul (@2, @1, TYPE_SIGN (TREE_TYPE (@1)), &ovf);
+      }
+      (if (ovf)
+       { constant_boolean_node (cmp == NE_EXPR, type); }
+       (cmp @0 { wide_int_to_tree (TREE_TYPE (@0), prod); }))))))))
+(for cmp (lt le gt ge)
+ (simplify
+  (cmp (exact_div @0 INTEGER_CST@1) INTEGER_CST@2)
+  (if (wi::gt_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1))))
+   (with
+    {
+      bool ovf;
+      wide_int prod = wi::mul (@2, @1, TYPE_SIGN (TREE_TYPE (@1)), &ovf);
+    }
+    (if (ovf)
+     { constant_boolean_node (wi::lt_p (@2, 0, TYPE_SIGN (TREE_TYPE (@2)))
+			      != (cmp == LT_EXPR || cmp == LE_EXPR), type); }
+     (cmp @0 { wide_int_to_tree (TREE_TYPE (@0), prod); }))))))
+
 /* Unordered tests if either argument is a NaN.  */
 (simplify
  (bit_ior (unordered @0 @0) (unordered @1 @1))
  (if (types_match (@0, @1))
   (unordered @0 @1)))
 (simplify
  (bit_and (ordered @0 @0) (ordered @1 @1))
  (if (types_match (@0, @1))
   (ordered @0 @1)))
 (simplify
Index: gcc/testsuite/gcc.dg/tree-ssa/cmpexactdiv.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/cmpexactdiv.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/cmpexactdiv.c	(working copy)
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+int f(int *p, int *q){
+  __SIZE_TYPE__ n = q - p;
+  return n == 0;
+}
+
+int g(int *p, int *q){
+  __PTRDIFF_TYPE__ n = q - p;
+  return n <= 2;
+}
+
+int h(long *p, long *q){
+  __SIZE_TYPE__ n = q - p;
+  return n == (__SIZE_TYPE__)(-1)/2;
+}
+
+/* { dg-final { scan-tree-dump-not "== 0" "optimized" } } */
+/* { dg-final { scan-tree-dump "<= 8" "optimized" { target { int32 } } } } */
+/* { dg-final { scan-tree-dump "return 0" "optimized" } } */

Reply via email to