This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Simplify floating point comparisons
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: Wilco Dijkstra <Wilco dot Dijkstra at arm dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>, nd <nd at arm dot com>
- Date: Wed, 18 Oct 2017 13:03:11 +0200
- Subject: Re: [PATCH] Simplify floating point comparisons
- Authentication-results: sourceware.org; auth=none
- References: <DB6PR0801MB205395FA43FC1A6547A981BC834C0@DB6PR0801MB2053.eurprd08.prod.outlook.com>
On Tue, Oct 17, 2017 at 6:28 PM, Wilco Dijkstra <Wilco.Dijkstra@arm.com> wrote:
> This patch implements some of the optimizations discussed in
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71026.
>
> Simplify (C / x > 0.0) into x > 0.0.
>
> If C is negative the comparison is reversed.
>
> Simplify (x * C1) > C2 into x > (C2 / C1).
>
> Again, if C1 is negative the comparison is reversed.
> Both transformations are only done with -funsafe-math-optimizations,
> the constant is non-zero, and not a NaN.
>
> OK for commit?
>
> ChangeLog
> 2017-10-17 Wilco Dijkstra <wdijkstr@arm.com>
> Jackson Woodruff <jackson.woodruff@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 test.
> --
> diff --git a/gcc/match.pd b/gcc/match.pd
> index e58a65af59b44a6b82ed8705f62966c5e6f251ac..cb48f079b4a310272e49cc319a1b3b0ff2023ba4 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -352,6 +352,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> (rdiv @0 (rdiv:s @1 @2))
> (mult (rdiv @0 @1) @2)))
>
> +(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.
There's also the underflow issue I guess this is what -funsafe-math-optimization
is for. I think ignoring underflows is dangerous though.
> + (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
> @@ -3546,6 +3559,20 @@ 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)
> + (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.
Existing overflows may be guarded against with a HONOR_INFINITIES check.
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?
Richard.
> /* 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..d051f052e13812c91cbd2d559bf2af8fae128ee1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/associate_comparison_1.c
> @@ -0,0 +1,34 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -funsafe-math-optimizations -fdump-tree-optimized" } */
> +
> +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-not " / " "optimized" } } */
>