]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
match.pd: Fold pattern of round semantics.
authorzhaozhou <zhaozhou@loongson.cn>
Thu, 23 Oct 2025 10:52:22 +0000 (18:52 +0800)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 23 Oct 2025 11:50:45 +0000 (13:50 +0200)
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.

gcc/match.pd
gcc/testsuite/gcc.dg/fold-round-1.c [new file with mode: 0644]

index a4248a521cfdef935b646e80a6079d262b74de7f..f7e074eaa564d955babe7ba0989bfd63efa27427 100644 (file)
@@ -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 (file)
index 0000000..0d7f954
--- /dev/null
@@ -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" } } */