From: Zhou Zhao <zhaoz...@loongson.cn>

This patch is a respond of the patch posted at
https://gcc.gnu.org/pipermail/gcc-patches/2025-August/693307.html
as some suggestion by Richard Biener, I have adopted these suggestions
and regenerated the patch.

In addition, I noticed that ignore the issue of expanding FLOOR and
CEIL in my pattern (for op(lt ge) bt(FLOOR CEIL)...), its will be fail
to cover all the expected patterns, and it will unfortunately cover
some unexpected patterns. Now I'm fixed this in the current submission.

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.
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                        | 21 +++++++++++
 gcc/testsuite/gcc.dg/fold-round-1.c | 56 +++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/fold-round-1.c

diff --git a/gcc/match.pd b/gcc/match.pd
index b1d7a3a1b73..788946af0f1 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 00000000000..0d7f95429ac
--- /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" } } */
-- 
2.20.1

Reply via email to