This patch is a respond of the patch posted at https://gcc.gnu.org/pipermail/gcc-patches/2025-January/673051.html as some suggestion by Richard Biener, I have adopted these suggestions and regenerated the patch.
In the 538.imagick_r benchmark of Spec2017, I find these pattern from MagickRound function. This patch implements these pattern in match.pd for 4 rules under -funsafe-math-optimizations: 1) (x-floor(x)) < (ceil(x)-x) ? floor(x) : ceil(x) -> floor(x+0.5) 2) (x-floor(x)) >= (ceil(x)-x) ? ceil(x) : floor(x) -> floor(x+0.5) 3) (ceil(x)-x) > (x-floor(x)) ? floor(x) : ceil(x) -> floor(x+0.5) 4) (ceil(x)-x) <= (x-floor(x)) ? ceil(x) : floor(x) -> floor(x+0.5) The patch implements floor(x+0.5) operation to replace these pattern that semantics of round(x) function. The patch was regtested on aarch64-linux-gnu and x86_64-linux-gnu, SPEC 2017 and SPEC 2006 were run: As for SPEC 2017, 538.imagick_r benchmark performance increased by 3%+ in base test of ratio mode. As for SPEC 2006, while the transform does not seem to be triggered, we also see no non-noise impact on performance. OK for mainline? gcc/ChangeLog: * match.pd: Add new pattern for round. gcc/testsuite/ChangeLog: * gcc.dg/fold-round-1.c: New test. --- gcc/match.pd | 17 +++++++++ gcc/testsuite/gcc.dg/fold-round-1.c | 56 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/fold-round-1.c diff --git a/gcc/match.pd b/gcc/match.pd index 66e8a787449..94036603e08 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -794,6 +794,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (rdiv @0 (negate @1)) (rdiv (negate @0) @1)) +(if (flag_unsafe_math_optimizations) +/* convert semantics of round(x) function to floor(x+0.5). */ +/* (x-floor(x)) < (ceil(x)-x) ? floor(x) : ceil(x) --> floor(x+0.5). */ +/* (x-floor(x)) >= (ceil(x)-x) ? ceil(x) : floor(x) --> floor(x+0.5). */ +/* (ceil(x)-x) > (x-floor(x)) ? floor(x) : ceil(x) --> floor(x+0.5). */ +/* (ceil(x)-x) <= (x-floor(x)) ? ceil(x) : floor(x) --> floor(x+0.5). */ +(for op (lt ge) + bt (FLOOR CEIL) + bf (CEIL FLOOR) + floor (FLOOR FLOOR) + ceil (CEIL CEIL) + (simplify + (cond (op:c (minus:s SSA_NAME@0 (floor SSA_NAME@0)) + (minus:s (ceil SSA_NAME@0) SSA_NAME@0)) + (bt SSA_NAME@0) (bf SSA_NAME@0)) + (floor (plus @0 { build_real (type, dconsthalf); }))))) + (if (flag_unsafe_math_optimizations) /* Simplify (C / x op 0.0) to x op 0.0 for C != 0, C != Inf/Nan. Since C / x may underflow to zero, do this only for unsafe math. */ diff --git a/gcc/testsuite/gcc.dg/fold-round-1.c b/gcc/testsuite/gcc.dg/fold-round-1.c new file mode 100644 index 00000000000..845d6d2e475 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-round-1.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -funsafe-math-optimizations" } */ + +extern void link_error (void); + +#define TEST_ROUND(TYPE, FFLOOR, FCEIL) \ + void round_##FFLOOR##_1 (TYPE x) \ + { \ + TYPE t1 = 0; \ + TYPE t2 = __builtin_##FFLOOR (x + 0.5); \ + if ((x - __builtin_##FFLOOR (x)) < (__builtin_##FCEIL (x) - x)) \ + t1 = __builtin_##FFLOOR (x); \ + else \ + t1 = __builtin_##FCEIL (x); \ + if (t1 != t2) \ + link_error (); \ + } \ + void round_##FFLOOR##_2 (TYPE x) \ + { \ + TYPE t1 = 0; \ + TYPE t2 = __builtin_##FFLOOR (x + 0.5); \ + if ((__builtin_##FCEIL (x) - x) > (x - __builtin_##FFLOOR (x))) \ + t1 = __builtin_##FFLOOR (x); \ + else \ + t1 = __builtin_##FCEIL (x); \ + if (t1 != t2) \ + link_error (); \ + } \ + void round_##FFLOOR##_3 (TYPE x) \ + { \ + TYPE t1 = 0; \ + TYPE t2 = __builtin_##FFLOOR (x + 0.5); \ + if ((__builtin_##FCEIL (x) - x) <= (x - __builtin_##FFLOOR (x))) \ + t1 = __builtin_##FCEIL (x); \ + else \ + t1 = __builtin_##FFLOOR (x); \ + if (t1 != t2) \ + link_error (); \ + } \ + void round_##FFLOOR##_4 (TYPE x) \ + { \ + TYPE t1 = 0; \ + TYPE t2 = __builtin_##FFLOOR (x + 0.5); \ + if ((x - __builtin_##FFLOOR (x)) >= (__builtin_##FCEIL (x) - x)) \ + t1 = __builtin_##FCEIL (x); \ + else \ + t1 = __builtin_##FFLOOR (x); \ + if (t1 != t2) \ + link_error (); \ + } + +TEST_ROUND (float, floorf, ceilf) +TEST_ROUND (double, floor, ceil) +TEST_ROUND (long double, floorl, ceill) + +/* { dg-final { scan-assembler-not "link_error" } } */ -- 2.20.1