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) {