ping (note also Jeff's reply https://gcc.gnu.org/ml/gcc-patches/2017-11/msg01916.html)
From: Wilco Dijkstra Sent: 15 November 2017 15:36 To: Richard Biener Cc: GCC Patches; nd Subject: Re: [PATCH] Simplify floating point comparisons Richard Biener wrote: > On Tue, Oct 17, 2017 at 6:28 PM, Wilco Dijkstra <wilco.dijks...@arm.com> > wrote: >> +(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))) > > Note that real_less (0., +Inf) so I think you either need to check C is > 'normal' > or ! HONOR_INFINITIES. Yes, it was missing an explicit check for infinity, now added. > There's also the underflow issue I guess this is what > -funsafe-math-optimizations > is for. I think ignoring underflows is dangerous though. We could change C / x > 0 to x >= 0 so the underflow case is included. However that still means x == 0.0 would behave differently - so the question is what exactly does -funsafe-math-optimization allow? >> + (for cmp (lt le gt ge) >> + neg_cmp (gt ge lt le) >> + /* Simplify (x * C1) cmp C2 -> x cmp (C2 / C1), where C1 != 0. */ >> + (simplify >> + (cmp (mult @0 REAL_CST@1) REAL_CST@2) >> + (with >> + { tree tem = const_binop (RDIV_EXPR, type, @2, @1); } >> + (if (tem) >> + (switch >> + (if (real_less (&dconst0, TREE_REAL_CST_PTR (@1))) >> + (cmp @0 { tem; })) >> + (if (real_less (TREE_REAL_CST_PTR (@1), &dconst0)) >> + (neg_cmp @0 { tem; }))))))) > > > Drops possible overflow/underflow in x * C1 and may create underflow > or overflow with C2/C1 which you should detect here at least. I've added checks for this, however I thought -funsafe-math-optimizations is allowed to insert/remove underflow/overflow, like in these cases: (x * 1e20f) * 1e20f and (x * 1e40f) * 1e-30f. > Existing overflows may be guarded against with a HONOR_INFINITIES check. Not sure what you mean with this? > When overflow/underflow can be disregarded is there any reason remaining to > make this guarded by flag_unsafe_math_optimizations? Are there any cases > where rounding issues can flip the comparison result? I think it needs to remain under -funsafe-math-optimizations. Here is the updated version: ChangeLog 2017-11-15 Wilco Dijkstra <wdijk...@arm.com> Jackson Woodruff <jackson.woodr...@arm.com> gcc/ PR 71026/tree-optimization * match.pd: Simplify floating point comparisons. gcc/testsuite/ PR 71026/tree-optimization * gcc.dg/associate_comparison_1.c: New. -- diff --git a/gcc/match.pd b/gcc/match.pd index 4d56847d6889923938625beb579b7bbb0cbbad91..967dbf8946fd12a161330f4c8b58dada5d9cb871 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -359,6 +359,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (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) + (if (!REAL_VALUE_ISINF (TREE_REAL_CST (@0))) + (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 @@ -3703,6 +3717,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (rdiv @2 @1)) (rdiv (op @0 @2) @1))) + (for cmp (lt le gt ge) + neg_cmp (gt ge lt le) + /* Simplify (x * C1) cmp C2 -> x cmp (C2 / C1), where C1 != 0. */ + (simplify + (cmp (mult @0 REAL_CST@1) REAL_CST@2) + (with + { tree tem = const_binop (RDIV_EXPR, type, @2, @1); } + (if (tem + && !(REAL_VALUE_ISINF (TREE_REAL_CST (tem)) + || (real_zerop (tem) && !real_zerop (@1)))) + (switch + (if (real_less (&dconst0, TREE_REAL_CST_PTR (@1))) + (cmp @0 { tem; })) + (if (real_less (TREE_REAL_CST_PTR (@1), &dconst0)) + (neg_cmp @0 { tem; }))))))) + /* 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..ceaba334cce770eb1cbec9283ba8a0c64f725630 --- /dev/null +++ b/gcc/testsuite/gcc.dg/associate_comparison_1.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funsafe-math-optimizations -fdump-tree-optimized-raw" } */ + +int +cmp_mul_1 (float x) +{ + return x * 3 <= 100; +} + +int +cmp_mul_2 (float x) +{ + return x * -5 > 100; +} + +int +div_cmp_1 (float x, float y) +{ + return x / 3 <= y; +} + +int +div_cmp_2 (float x, float y) +{ + return x / 3 <= 1; +} + +int +inv_cmp (float x) +{ + return 5 / x >= 0; +} + +/* { dg-final { scan-tree-dump-times "mult_expr" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "rdiv_expr" "optimized" } } */