This patch implements 4 rules for semantics of round func in match.pd 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 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 | 27 ++++++++++++++ gcc/testsuite/gcc.dg/fold-round-1.c | 56 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/fold-round-1.c diff --git a/gcc/match.pd b/gcc/match.pd index 83eca8b2e0a..7b22b7913ac 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -777,6 +777,33 @@ 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 (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); })))) +(for op (gt le) + bt (FLOOR CEIL) + bf (CEIL FLOOR) + floor (FLOOR FLOOR) + ceil (CEIL CEIL) + (simplify + (cond (op (minus:s (ceil SSA_NAME@0) SSA_NAME@0) + (minus:s SSA_NAME@0 (floor 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