diff mbox series

[v3,6/6] powerpc: Use generic ilogb/ilogbf and refactor ilogbf128

Message ID 20250429164007.2928271-7-adhemerval.zanella@linaro.org
State New
Headers show
Series Remove UB and optimize ilogbf/ilogb | expand

Commit Message

Adhemerval Zanella April 29, 2025, 4:30 p.m. UTC
The powerpc64 leverages the use of xsxexpdp and xsxexpqp for
for both ilogb/ilogbf for float, double, and float128 types.
However with the new generic ilogb/ilogbf, this is not really
a gain anymore.

On POWER9 with gcc-13, the xsxexpdp/xsxexpqp shows:

$ ./benchtests/bench-ilogb
  "ilogb": {
   "subnormal": {
    "duration": 5.08829e+08,
    "iterations": 4.4588e+07,
    "max": 18.761,
    "min": 6.7005,
    "mean": 11.4118
   },
   "normal": {
    "duration": 5.04674e+08,
    "iterations": 9.9596e+07,
    "max": 7.386,
    "min": 5.0505,
    "mean": 5.06722
   }
$ ./benchtests/bench-ilogbf
  "ilogbf": {
   "subnormal": {
    "duration": 5.04918e+08,
    "iterations": 9.8732e+07,
    "max": 7.1595,
    "min": 5.0475,
    "mean": 5.11402
   },
   "normal": {
    "duration": 5.04971e+08,
    "iterations": 9.8744e+07,
    "max": 7.771,
    "min": 5.048,
    "mean": 5.11394
   }
  }

While the new generic implementation shows:

$ ./benchtests/bench-ilogb
  "ilogb": {
   "subnormal": {
    "duration": 5.05389e+08,
    "iterations": 9.2644e+07,
    "max": 11.0355,
    "min": 5.4255,
    "mean": 5.45517
   },
   "normal": {
    "duration": 5.04667e+08,
    "iterations": 1.02388e+08,
    "max": 9.758,
    "min": 4.8945,
    "mean": 4.92897
   }
  }[azanella@cfarm135 powerpc64le-linux-gnu-power9-gcc13]$ ./benchtests/bench-ilogbf
  "ilogbf": {
   "subnormal": {
    "duration": 5.05409e+08,
    "iterations": 9.238e+07,
    "max": 7.69,
    "min": 5.442,
    "mean": 5.47098
   },
   "normal": {
    "duration": 5.0456e+08,
    "iterations": 1.02012e+08,
    "max": 6.84,
    "min": 4.922,
    "mean": 4.94609
   }
  }

The xsxexpdp/xsxexpqp also adds some extra code size overhead since it
uses the generic ilogb/ilogbf for 0/inf/NaN handling.  It is still kept
for float128, and this patch also optimizes it to avoid need to call
extra generic symbol to handle not number inputs.

On same hardware (POWER9/gcc-13) it shows the improvement:

* master

  "ilogbf128": {
   "subnormal": {
    "duration": 5.09608e+08,
    "iterations": 3.3092e+07,
    "max": 28.845,
    "min": 6.824,
    "mean": 15.3997
   },
   "normal": {
    "duration": 5.05148e+08,
    "iterations": 9.1692e+07,
    "max": 7.744,
    "min": 5.377,
    "mean": 5.50918
   }
  }

* patch:

  "ilogbf128": {
   "subnormal": {
    "duration": 5.0586e+08,
    "iterations": 8.388e+07,
    "max": 7.3295,
    "min": 5.952,
    "mean": 6.03076
   },
   "normal": {
    "duration": 5.04783e+08,
    "iterations": 9.6608e+07,
    "max": 8.9255,
    "min": 5.185,
    "mean": 5.22507
   }
  }

Checked on powerpc64le-linux-gnu and powerpc64le-linux-gnu targetting
POWER8 and with --disable-multi-arch on POWER9.
---
 sysdeps/powerpc/powerpc64/le/fpu/e_ilogb.c    | 41 -------------
 sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf.c   | 41 -------------
 .../powerpc/powerpc64/le/fpu/e_ilogbf128.c    |  1 +
 .../powerpc/powerpc64/le/fpu/e_llogbf128.c    |  1 +
 .../powerpc64/le/fpu/multiarch/Makefile       |  2 +-
 sysdeps/powerpc/powerpc64/le/fpu/w_ilogb.c    |  2 -
 .../powerpc64/le/fpu/w_ilogb_template.c       | 30 ----------
 sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf.c   |  2 -
 .../powerpc64/le/fpu/w_ilogbf128-impl.h       | 57 +++++++++++++++++++
 .../powerpc64/le/fpu/w_ilogbf128-power9.c     |  1 +
 .../powerpc/powerpc64/le/fpu/w_ilogbf128.c    | 51 +++++++++++++++++
 sysdeps/powerpc/powerpc64/le/fpu/w_llogb.c    |  2 -
 sysdeps/powerpc/powerpc64/le/fpu/w_llogbf.c   |  2 -
 .../powerpc64/le/fpu/w_llogbf128-power9.c     |  1 +
 .../powerpc/powerpc64/le/fpu/w_llogbf128.c    |  2 +
 15 files changed, 115 insertions(+), 121 deletions(-)
 delete mode 100644 sysdeps/powerpc/powerpc64/le/fpu/e_ilogb.c
 delete mode 100644 sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf.c
 create mode 100644 sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf128.c
 create mode 100644 sysdeps/powerpc/powerpc64/le/fpu/e_llogbf128.c
 delete mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_ilogb.c
 delete mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_ilogb_template.c
 delete mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf.c
 create mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-impl.h
 create mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-power9.c
 create mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128.c
 delete mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_llogb.c
 delete mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_llogbf.c
 create mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128-power9.c
 create mode 100644 sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128.c
diff mbox series

Patch

diff --git a/sysdeps/powerpc/powerpc64/le/fpu/e_ilogb.c b/sysdeps/powerpc/powerpc64/le/fpu/e_ilogb.c
deleted file mode 100644
index 89e7498266..0000000000
--- a/sysdeps/powerpc/powerpc64/le/fpu/e_ilogb.c
+++ /dev/null
@@ -1,41 +0,0 @@ 
-/* Get integer exponent of a floating-point value.
-   Copyright (C) 1999-2025 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <limits.h>
-#include <math.h>
-#include <stdbit.h>
-#include "math_config.h"
-
-int
-__ieee754_ilogb (double x)
-{
-  uint64_t ux = asuint64 (x);
-  int ex = (ux & ~SIGN_MASK) >> MANTISSA_WIDTH;
-  if (ex == 0) /* zero or subnormal */
-    {
-      /* Clear sign and exponent */
-      ux <<= 12;
-      if (ux == 0)
-	return FP_ILOGB0;
-      /* subnormal  */
-      return -1023 - stdc_leading_zeros (ux);
-    }
-  if (ex == EXPONENT_MASK >> MANTISSA_WIDTH) /* NaN or Inf */
-    return ux << 12 ? FP_ILOGBNAN : INT_MAX;
-  return ex - 1023;
-}
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf.c b/sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf.c
deleted file mode 100644
index 1c2a8a5ade..0000000000
--- a/sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf.c
+++ /dev/null
@@ -1,41 +0,0 @@ 
-/* Get integer exponent of a floating-point value.
-   Copyright (C) 1999-2025 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <limits.h>
-#include <math.h>
-#include <stdbit.h>
-#include "sysdeps/ieee754/flt-32/math_config.h"
-
-int
-__ieee754_ilogbf (float x)
-{
-  uint32_t ux = asuint (x);
-  int ex = (ux & ~SIGN_MASK) >> MANTISSA_WIDTH;
-  if (ex == 0) /* zero or subnormal */
-    {
-      /* Clear sign and exponent.  */
-      ux <<= 1 + EXPONENT_WIDTH;
-      if (ux == 0)
-	return FP_ILOGB0;
-      /* sbunormal */
-      return -127 - stdc_leading_zeros (ux);
-    }
-  if (ex == EXPONENT_MASK >> MANTISSA_WIDTH) /* NaN or Inf */
-    return ux << (1 + EXPONENT_WIDTH) ? FP_ILOGBNAN : INT_MAX;
-  return ex - 127;
-}
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf128.c b/sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf128.c
new file mode 100644
index 0000000000..4ec3582ae4
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/fpu/e_ilogbf128.c
@@ -0,0 +1 @@ 
+/* Not needed, implemented at w_ilogbf128.c */
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/e_llogbf128.c b/sysdeps/powerpc/powerpc64/le/fpu/e_llogbf128.c
new file mode 100644
index 0000000000..163d9e2523
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/fpu/e_llogbf128.c
@@ -0,0 +1 @@ 
+/* Not needed, implemented at w_llogbf128.c */
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/multiarch/Makefile b/sysdeps/powerpc/powerpc64/le/fpu/multiarch/Makefile
index 6d74f09912..72adc6463b 100644
--- a/sysdeps/powerpc/powerpc64/le/fpu/multiarch/Makefile
+++ b/sysdeps/powerpc/powerpc64/le/fpu/multiarch/Makefile
@@ -90,7 +90,7 @@  gen-libm-f128-ifunc-routines = \
 	e_acosf128 e_acoshf128 e_asinf128 e_atan2f128 e_atanhf128 e_coshf128 \
 	e_expf128 e_fmodf128 e_hypotf128 e_j0f128 e_j1f128 e_jnf128 \
 	e_lgammaf128_r e_logf128 e_log10f128 e_powf128 e_remainderf128 \
-	e_sinhf128 e_sqrtf128 e_gammaf128_r e_ilogbf128 k_tanf128 s_asinhf128 \
+	e_sinhf128 e_sqrtf128 e_gammaf128_r k_tanf128 s_asinhf128 \
 	s_atanf128 s_cbrtf128 s_ceilf128 s_cosf128 s_erff128 s_exp10m1f128 \
 	s_exp2m1f128 s_expm1f128 \
 	s_fabsf128 s_floorf128 s_log1pf128 s_logbf128 \
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb.c b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb.c
deleted file mode 100644
index 9c26217021..0000000000
--- a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb.c
+++ /dev/null
@@ -1,2 +0,0 @@ 
-#include <math-type-macros-double.h>
-#include <w_ilogb_template.c>
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb_template.c b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb_template.c
deleted file mode 100644
index b5c1c0aa9d..0000000000
--- a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogb_template.c
+++ /dev/null
@@ -1,30 +0,0 @@ 
-#include <math.h>
-#include <errno.h>
-#include <limits.h>
-#include <math_private.h>
-#include <fenv.h>
-
-#if _GL_HAS_BUILTIN_ILOGB
-int
-M_DECL_FUNC (__ilogb) (FLOAT x)
-{
-  int r;
-  /* Check for exceptional cases.  */
-  if (! M_SUF(__builtin_test_dc_ilogb) (x, 0x7f))
-    r = M_SUF (__builtin_ilogb) (x);
-  else
-    /* Fallback to the generic ilogb if x is NaN, Inf or subnormal.  */
-    r = M_SUF (__ieee754_ilogb) (x);
-  if (__builtin_expect (r == FP_ILOGB0, 0)
-      || __builtin_expect (r == FP_ILOGBNAN, 0)
-      || __builtin_expect (r == INT_MAX, 0))
-    {
-      __set_errno (EDOM);
-      __feraiseexcept (FE_INVALID);
-    }
-  return r;
-}
-declare_mgen_alias (__ilogb, ilogb)
-#else
-#include <math/w_ilogb_template.c>
-#endif
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf.c b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf.c
deleted file mode 100644
index 047ad4bf11..0000000000
--- a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf.c
+++ /dev/null
@@ -1,2 +0,0 @@ 
-#include <math-type-macros-float.h>
-#include <w_ilogb_template.c>
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-impl.h b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-impl.h
new file mode 100644
index 0000000000..dff5331331
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-impl.h
@@ -0,0 +1,57 @@ 
+/* Get integer exponent of a floating-point value.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* Use the double version of EDOM/invalid operation handling.  */
+#include "math_config.h"
+
+static RET_TYPE
+llogb_nan_inf_subnormal (uint64_t hx, uint64_t lx)
+{
+  if (hx <= 0x0001000000000000ULL)
+    {
+      /* Zero or subnormal.  */
+      if ((hx | lx) == 0)
+	return RET_INVALID (RET_LOGB0);
+      /* Subnormal */
+      if (hx == 0)
+	return -16431L - stdc_leading_zeros (lx);
+      else
+	return -16382L - stdc_leading_zeros (hx << 15);
+    }
+  return RET_INVALID (RET_LOGBNAN);
+}
+
+static inline RET_TYPE
+IMPL_NAME (FLOAT x)
+{
+  uint64_t hx, lx;
+  GET_FLOAT128_WORDS64 (hx, lx, x);
+  hx &= 0x7fffffffffffffffULL;
+
+#if _GL_HAS_BUILTIN_ILOGB
+  /* Check for exceptional cases.  */
+  if (__glibc_likely (! M_SUF(__builtin_test_dc_ilogb) (x, 0x7f)))
+    return M_SUF (__builtin_ilogb) (x);
+#else
+  if (__glibc_likely (hx < 0x7fff000000000000ULL
+		      && hx > 0x0001000000000000ULL))
+    return (hx >> 48) - 0x3fff;
+#endif
+
+  return llogb_nan_inf_subnormal (hx, lx);
+}
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-power9.c b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-power9.c
new file mode 100644
index 0000000000..9de3f2101e
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128-power9.c
@@ -0,0 +1 @@ 
+#include "w_ilogbf128.c"
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128.c b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128.c
new file mode 100644
index 0000000000..ae3e4a9e48
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/fpu/w_ilogbf128.c
@@ -0,0 +1,51 @@ 
+/* Get integer exponent of a floating-point value.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <math-type-macros-float128.h>
+#include <math.h>
+#include <math_private.h>
+#include <stdbit.h>
+
+#ifdef DEF_AS_LLOGBF128
+# define DECL_NAME   __llogb
+# define FUNC_NAME   llogb
+# define RET_TYPE    long int
+# define RET_LOGB0   FP_LLOGB0
+# define RET_LOGBNAN FP_LLOGBNAN
+# define RET_LOGMAX  LONG_MAX
+# define RET_INVALID __math_invalid_li
+#else
+# define DECL_NAME   __ilogb
+# define FUNC_NAME   ilogb
+# define RET_TYPE    int
+# define RET_LOGB0   FP_ILOGB0
+# define RET_LOGBNAN FP_ILOGBNAN
+# define RET_LOGMAX  INT_MAX
+# define RET_INVALID __math_invalid_i
+#endif
+#define __IMPL_NAME(x,y) x ## _ ## y
+#define _IMPL_NAME(x,y)  __IMPL_NAME(x,y)
+#define IMPL_NAME        _IMPL_NAME(FUNC_NAME, impl)
+#include <w_ilogbf128-impl.h>
+
+RET_TYPE
+M_DECL_FUNC (DECL_NAME) (FLOAT x)
+{
+  return IMPL_NAME (x);
+}
+declare_mgen_alias (DECL_NAME, FUNC_NAME)
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_llogb.c b/sysdeps/powerpc/powerpc64/le/fpu/w_llogb.c
deleted file mode 100644
index 5e8891a668..0000000000
--- a/sysdeps/powerpc/powerpc64/le/fpu/w_llogb.c
+++ /dev/null
@@ -1,2 +0,0 @@ 
-#include <math-type-macros-double.h>
-#include <w_llogb_template.c>
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf.c b/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf.c
deleted file mode 100644
index edb7e9a9e6..0000000000
--- a/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf.c
+++ /dev/null
@@ -1,2 +0,0 @@ 
-#include <math-type-macros-float.h>
-#include <w_llogb_template.c>
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128-power9.c b/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128-power9.c
new file mode 100644
index 0000000000..9550611b95
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128-power9.c
@@ -0,0 +1 @@ 
+#include "w_llogbf128.c"
diff --git a/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128.c b/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128.c
new file mode 100644
index 0000000000..0a67251faa
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/fpu/w_llogbf128.c
@@ -0,0 +1,2 @@ 
+#define DEF_AS_LLOGBF128
+#include "w_ilogbf128.c"