https://gcc.gnu.org/g:fe9f0719d8ebd2bb3e6e1ecd3b3167931d42dabd
commit r16-4576-gfe9f0719d8ebd2bb3e6e1ecd3b3167931d42dabd Author: zhaozhou <[email protected]> Date: Thu Oct 23 18:52:22 2025 +0800 match.pd: Fold pattern of round semantics. 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: 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. gcc/ChangeLog: * match.pd: Add new pattern for round. gcc/testsuite/ChangeLog: * gcc.dg/fold-round-1.c: New test. Diff: --- gcc/match.pd | 21 ++++++++++++++ gcc/testsuite/gcc.dg/fold-round-1.c | 56 +++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/gcc/match.pd b/gcc/match.pd index a4248a521cfd..f7e074eaa564 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -794,6 +794,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (rdiv @0 (negate @1)) (rdiv (negate @0) @1)) +/* 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 lt lt lt ge ge ge ge) + bt (BUILT_IN_FLOORF BUILT_IN_FLOOR BUILT_IN_FLOORL IFN_FLOOR + BUILT_IN_CEILF BUILT_IN_CEIL BUILT_IN_CEILL IFN_CEIL) + bf (BUILT_IN_CEILF BUILT_IN_CEIL BUILT_IN_CEILL IFN_CEIL + BUILT_IN_FLOORF BUILT_IN_FLOOR BUILT_IN_FLOORL IFN_FLOOR) + floor (BUILT_IN_FLOORF BUILT_IN_FLOOR BUILT_IN_FLOORL IFN_FLOOR + BUILT_IN_FLOORF BUILT_IN_FLOOR BUILT_IN_FLOORL IFN_FLOOR) + ceil (BUILT_IN_CEILF BUILT_IN_CEIL BUILT_IN_CEILL IFN_CEIL + BUILT_IN_CEILF BUILT_IN_CEIL BUILT_IN_CEILL IFN_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)) + (if (!HONOR_SIGNED_ZEROS (type) && !HONOR_SIGN_DEPENDENT_ROUNDING (type)) + (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 000000000000..0d7f95429ac3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-round-1.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast" } */ + +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" } } */
