Hi all,

Apologies again to those CC'ed, who (again) received this twice.

Joseph: Yes you are correct. I misread the original thread, now fixed.

Richard: I've moved the optimizations out of fold-const.c. One has been replicated in match.pd, and the other (x / C +- y / C -> (x +- y) / C) I've deleted as it only introduced a new optimization when running with the flags '-O0 -funsafe-math-optimizations'.

On O1 and up, the pattern that replaces 'x / C' with 'x * (1 / C)'
is enabled and then the pattern is covered by that and
(x * C +- y * C -> C * (x +- y)) (which is already present in match.pd)

I have also updated the testcase for those optimizations to use 'O1' to avoid that case.


On 08/24/2017 10:06 PM, Jeff Law wrote:
On 08/17/2017 03:55 AM, Wilco Dijkstra wrote:
Richard Biener wrote:
On Tue, Aug 15, 2017 at 4:11 PM, Wilco Dijkstra <wilco.dijks...@arm.com> wrote:
Richard Biener wrote:
We also change the association of

       x / (y * C) -> (x / C) / y

If C is a constant.

Why's that profitable?

It enables (x * C1) / (y * C2) -> (x * C1/C2) / y for example.
Also 1/y is now available to the reciprocal optimization, see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71026 for details.

Sure, but on its own it's going to be slower.  So this isn't the
correct way to enable those followup transforms.

How can it be any slower? It's one division and one multiply in both cases.
x / (y * C) -> (x / C) / y

Goes from one division and one multiplication to two divisions.  I'm
guessing that's what Richi is (reasonably) concerned about.

So it may be the case that we need more complex pattern matching here
for when to perform the first transformation to ultimately enable the
second.


The only case where we don't remove the division but still execute this pattern is when run with'-O0 -freciprocal-math'.

As long as we have 'O1' or greater (and -freciprocal-math), that is enough to enable the removal of the reciprocal.


Jackson.


Jeff

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 
eeeff1ed166734328a612142fdf6235274f9e858..907d96c3d994db1ec8dc0ef692ac0b4d59c99a4c
 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -3834,47 +3834,6 @@ invert_truthvalue_loc (location_t loc, tree arg)
                               : TRUTH_NOT_EXPR,
                          type, arg);
 }
-
-/* Knowing that ARG0 and ARG1 are both RDIV_EXPRs, simplify a binary operation
-   with code CODE.  This optimization is unsafe.  */
-static tree
-distribute_real_division (location_t loc, enum tree_code code, tree type,
-                         tree arg0, tree arg1)
-{
-  bool mul0 = TREE_CODE (arg0) == MULT_EXPR;
-  bool mul1 = TREE_CODE (arg1) == MULT_EXPR;
-
-  /* (A / C) +- (B / C) -> (A +- B) / C.  */
-  if (mul0 == mul1
-      && operand_equal_p (TREE_OPERAND (arg0, 1),
-                      TREE_OPERAND (arg1, 1), 0))
-    return fold_build2_loc (loc, mul0 ? MULT_EXPR : RDIV_EXPR, type,
-                       fold_build2_loc (loc, code, type,
-                                    TREE_OPERAND (arg0, 0),
-                                    TREE_OPERAND (arg1, 0)),
-                       TREE_OPERAND (arg0, 1));
-
-  /* (A / C1) +- (A / C2) -> A * (1 / C1 +- 1 / C2).  */
-  if (operand_equal_p (TREE_OPERAND (arg0, 0),
-                      TREE_OPERAND (arg1, 0), 0)
-      && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
-      && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
-    {
-      REAL_VALUE_TYPE r0, r1;
-      r0 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
-      r1 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
-      if (!mul0)
-       real_arithmetic (&r0, RDIV_EXPR, &dconst1, &r0);
-      if (!mul1)
-        real_arithmetic (&r1, RDIV_EXPR, &dconst1, &r1);
-      real_arithmetic (&r0, code, &r0, &r1);
-      return fold_build2_loc (loc, MULT_EXPR, type,
-                         TREE_OPERAND (arg0, 0),
-                         build_real (type, r0));
-    }
-
-  return NULL_TREE;
-}
 
 /* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
    starting at BITPOS.  The field is unsigned if UNSIGNEDP is nonzero
@@ -9419,12 +9378,6 @@ fold_binary_loc (location_t loc,
                }
            }
 
-         if (flag_unsafe_math_optimizations
-             && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == 
MULT_EXPR)
-             && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == 
MULT_EXPR)
-             && (tem = distribute_real_division (loc, code, type, arg0, arg1)))
-           return tem;
-
           /* Convert a + (b*c + d*e) into (a + b*c) + d*e.
              We associate floats only if the user has specified
              -fassociative-math.  */
@@ -9772,13 +9725,6 @@ fold_binary_loc (location_t loc,
            return tem;
        }
 
-      if (FLOAT_TYPE_P (type)
-         && flag_unsafe_math_optimizations
-         && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
-         && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
-         && (tem = distribute_real_division (loc, code, type, arg0, arg1)))
-       return tem;
-
       /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the same or
         one.  Make sure the type is not saturating and has the signedness of
         the stripped operands, as fold_plusminus_mult_expr will re-associate.
diff --git a/gcc/match.pd b/gcc/match.pd
index 
e98db52af84946cf579c6434e06d450713a47162..2714b404826c2b4c74e3f382b85bf2ec183ee4f8
 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -342,16 +342,41 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (negate @0)))
 
 (if (flag_reciprocal_math)
- /* Convert (A/B)/C to A/(B*C)  */
+ /* Convert (A/B)/C to A/(B*C) where neither B nor C are constant.  */
  (simplify
   (rdiv (rdiv:s @0 @1) @2)
-   (rdiv @0 (mult @1 @2)))
+   (if (TREE_CODE (@1) != REAL_CST && TREE_CODE (@1) != REAL_CST)
+    (rdiv @0 (mult @1 @2))))
+
+ /* Simplify x / (C * y) to (x / C) / y where C is a constant.  */
+ (simplify
+  (rdiv @0
+   (mult @1 REAL_CST@2))
+  (rdiv (rdiv @0 @2) @1))
 
  /* Convert A/(B/C) to (A/B)*C  */
  (simplify
   (rdiv @0 (rdiv:s @1 @2))
    (mult (rdiv @0 @1) @2)))
 
+/* Simplify x / (- y) to -x / y.  */
+(simplify
+ (rdiv @0 (negate @1))
+ (rdiv (negate @0) @1))
+
+(if (flag_unsafe_math_optimizations)
+  /* Simplify (C / x op 0.0) to x op 0.0 for C > 0.  */
+  (for op (lt le gt ge)
+       neg_op (gt ge lt le)
+    (simplify
+      (op (rdiv REAL_CST@0 @1) real_zerop@2)
+      (switch
+       (if (real_less (&dconst0, TREE_REAL_CST_PTR (@0)))
+       (op @1 @2))
+       /* For C < 0, use the inverted operator.  */
+       (if (real_less (TREE_REAL_CST_PTR (@0), &dconst0))
+       (neg_op @1 @2))))))
+
 /* Optimize (X & (-A)) / A where A is a power of 2, to X >> log2(A) */
 (for div (trunc_div ceil_div floor_div round_div exact_div)
  (simplify
@@ -610,15 +635,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (tem)
      (rdiv { tem; } @1)))))
 
-/* Convert C1/(X*C2) into (C1/C2)/X  */
-(simplify
- (rdiv REAL_CST@0 (mult @1 REAL_CST@2))
-  (if (flag_reciprocal_math)
-   (with
-    { tree tem = const_binop (RDIV_EXPR, type, @0, @2); }
-    (if (tem)
-     (rdiv { tem; } @1)))))
-
 /* Simplify ~X & X as zero.  */
 (simplify
  (bit_and:c (convert? @0) (convert? (bit_not @0)))
@@ -3446,6 +3462,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (if (!HONOR_SNANS (type))
    @0))
 
+ (for cmp (lt le gt ge)
+      neg_cmp (gt ge lt le)
+  /* Simplify (x / C1) cmp y -> x cmp y * C1.  */
+  (simplify
+   (cmp (rdiv @0 REAL_CST@1) @2)
+   (switch
+    (if (real_less (&dconst0, TREE_REAL_CST_PTR (@1)))
+     (cmp @0 (mult @2 @1)))
+    (if (real_less (TREE_REAL_CST_PTR (@1), &dconst0))
+     (neg_cmp @0 (mult @2 @1)))))
+
+  /* Simplify (x * C1) cmp C2 -> x cmp C2 / C1, where C1 != 0.  */
+  (simplify
+   (cmp (mult @0 REAL_CST@1) REAL_CST@2)
+   (switch
+    (if (real_less (&dconst0, TREE_REAL_CST_PTR (@1)))
+     (cmp @0 (rdiv @2 @1)))
+    (if (real_less (TREE_REAL_CST_PTR (@1), &dconst0))
+     (neg_cmp @0 (rdiv @2 @1))))))
+
+  (for op (plus minus)
+   /* Simplify (A / C) +- (B / C) -> (A +- B) / C.  */
+   (simplify
+    (op (rdiv @0 @1)
+       (rdiv @2 @1))
+    (rdiv (op @0 @2) @1)))
+
+
  /* Simplify sqrt(x) * sqrt(y) -> sqrt(x*y).  */
  (for root (SQRT CBRT)
   (simplify
diff --git a/gcc/testsuite/gcc.dg/associate_comparison_1.c 
b/gcc/testsuite/gcc.dg/associate_comparison_1.c
new file mode 100644
index 
0000000000000000000000000000000000000000..d0a197b48d660d3f2e9fabda855670ba477afc4d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/associate_comparison_1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-funsafe-math-optimizations -fdump-tree-optimized" } */
+
+int
+lt_cmp (float x, float y)
+{
+  return x / 2 <= 0;
+}
+
+int lt_cmp_2 (float x, float y)
+{
+  return x / 3 <= y;
+}
+
+int
+inv_cmp (float x, float y)
+{
+  return 5 / x >= 0;
+}
+
+
+/* { dg-final { scan-tree-dump-not " / " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/fold-div-1.c 
b/gcc/testsuite/gcc.dg/fold-div-1.c
index 
c1c7250f882cfed7705ba60994e47440580f4c76..73b75861166f40733d9768e9703664d51ee1a9ef
 100644
--- a/gcc/testsuite/gcc.dg/fold-div-1.c
+++ b/gcc/testsuite/gcc.dg/fold-div-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-funsafe-math-optimizations -fdump-tree-gimple" } */
+/* { dg-options "-O1 -funsafe-math-optimizations -fdump-tree-gimple" } */
 
 float f(float x)
 {

Reply via email to