This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Simplify floating point comparisons


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" } } */
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]