From e6f82439d5088c57344f0bc1113ecf8c4cc0a42a Mon Sep 17 00:00:00 2001 From: Jeongkeun Kim Date: Mon, 30 Mar 2026 10:29:42 +0900 Subject: [PATCH] math: extend non-glibc guard to Clang and add exp10 guard The previous fix (#1398) guarded __builtin_roundeven only for GCC 10+, assuming Clang always lowers it to an inline llvm.roundeven.* intrinsic. That assumption is wrong: Clang emits a roundeven()/roundevenf() libm call on targets without a native rounding instruction (x86 without SSE4.1, powerpc, sparc, i386, etc.). On non-glibc systems (musl, OpenBSD, FreeBSD, MinGW) the symbol is absent, causing: undefined reference to 'roundevenf' Fix: drop the GCC-only restriction and apply the glibc >= 2.25 guard to all compilers. Non-glibc platforms fall through to the existing portable inline fallback. Also guard __builtin_exp10 / __builtin_exp10f: exp10() is a GNU extension present only in glibc, so the builtin produces the same class of link error on musl and other non-glibc libcs. The fallback simde_math_pow(10.0, v) / simde_math_powf(10.0f, v) is already present and correct. Reported by brad0 in issue #1396. --- simde/simde-math.h | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/simde/simde-math.h b/simde/simde-math.h index 9685d903d..0a5a4a3fb 100644 --- a/simde/simde-math.h +++ b/simde/simde-math.h @@ -973,13 +973,18 @@ simde_math_fpclass(double v, const int imm8) { #endif #endif -#if HEDLEY_HAS_BUILTIN(__builtin_exp10) || HEDLEY_GCC_VERSION_CHECK(3,4,0) +/* __builtin_exp10 lowers to exp10() which is a GNU extension available + * only in glibc. Other libcs (musl, OpenBSD, FreeBSD, MinGW, etc.) + * lack the symbol and produce a link error. Fall back to pow(10, v). */ +#if (HEDLEY_HAS_BUILTIN(__builtin_exp10) || HEDLEY_GCC_VERSION_CHECK(3,4,0)) && \ + defined(__GLIBC__) # define simde_math_exp10(v) __builtin_exp10(v) #else # define simde_math_exp10(v) simde_math_pow(10.0, (v)) #endif -#if HEDLEY_HAS_BUILTIN(__builtin_exp10f) || HEDLEY_GCC_VERSION_CHECK(3,4,0) +#if (HEDLEY_HAS_BUILTIN(__builtin_exp10f) || HEDLEY_GCC_VERSION_CHECK(3,4,0)) && \ + defined(__GLIBC__) # define simde_math_exp10f(v) __builtin_exp10f(v) #else # define simde_math_exp10f(v) simde_math_powf(10.0f, (v)) @@ -1266,17 +1271,16 @@ simde_math_fpclass(double v, const int imm8) { #endif #if !defined(simde_math_roundeven) - /* GCC 10+ lowers __builtin_roundeven to a libm roundeven() call when - * the target has no native instruction. roundeven() is C23 and only - * available in glibc >= 2.25; other platforms (musl, OpenBSD, MinGW, - * etc.) lack the symbol and produce a link error. Clang lowers the - * builtin to an llvm.roundeven.* intrinsic which is always emitted - * inline (no libm dependency), so the GCC guard is not needed there. */ + /* __builtin_roundeven lowers to a roundeven() libm call on targets + * without a native rounding instruction (x86 without SSE4.1, + * powerpc, sparc, i386, etc.). roundeven() is C23 and only + * available in glibc >= 2.25; other libcs (musl, OpenBSD, FreeBSD, + * MinGW, etc.) lack the symbol and produce a link error. Guard for + * all compilers: non-glibc platforms use the inline fallback below. */ #if \ ((!defined(HEDLEY_EMSCRIPTEN_VERSION) || HEDLEY_EMSCRIPTEN_VERSION_CHECK(3, 1, 43)) && \ HEDLEY_HAS_BUILTIN(__builtin_roundeven) && \ - (!HEDLEY_GCC_VERSION_CHECK(10,0,0) || \ - (defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))))) + (defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)))) #define simde_math_roundeven(v) __builtin_roundeven(v) #elif defined(simde_math_round) && defined(simde_math_fabs) static HEDLEY_INLINE @@ -1295,13 +1299,12 @@ simde_math_fpclass(double v, const int imm8) { #if !defined(simde_math_roundevenf) /* Same rationale as simde_math_roundeven above; applies to the float - * variant. GCC 10+ requires glibc >= 2.25 for roundevenf(); Clang - * is always safe via llvm.roundeven.f32 inline expansion. */ + * variant. Both GCC and Clang emit a roundevenf() libm call on + * targets without a native instruction. */ #if \ ((!defined(HEDLEY_EMSCRIPTEN_VERSION) || HEDLEY_EMSCRIPTEN_VERSION_CHECK(3, 1, 43)) && \ HEDLEY_HAS_BUILTIN(__builtin_roundevenf) && \ - (!HEDLEY_GCC_VERSION_CHECK(10,0,0) || \ - (defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))))) + (defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)))) #define simde_math_roundevenf(v) __builtin_roundevenf(v) #elif defined(simde_math_roundf) && defined(simde_math_fabsf) static HEDLEY_INLINE