math: guard __builtin_roundeven against non-glibc platforms#1398
math: guard __builtin_roundeven against non-glibc platforms#1398mr-c merged 2 commits intosimd-everywhere:masterfrom
Conversation
|
@kjg0724 if you could add one architecture + compiler combination to our CI, which would have caught this issue sooner, what would it be? |
|
GCC 10+ on Alpine Linux (musl libc) with |
Thank you! Can you add this to our CI matrix? You are welcome to use whichever CI provider you please (minor bonus if it isn't GitHub Actions as we have so many there already). |
|
And if you could squash your existing 3 commits into one, that would be appreciated. I can do it myself, but maybe you would craft the combined commit message better than I would. |
roundeven() / roundevenf() are C23 functions added to glibc 2.25 (2017). On GCC 10+, HEDLEY_HAS_BUILTIN(__builtin_roundeven) returns true (both __has_builtin and __builtin_roundeven were introduced in GCC 10), so the builtin path is taken. GCC lowers this to a roundeven() libm call when the target has no native instruction (ROUNDSD/FRINTN). On non-glibc platforms (musl, OpenBSD, MinGW, etc.) this symbol is absent, causing a link error: undefined reference to 'roundevenf' Note: the previous HEDLEY_GCC_VERSION_CHECK(10,0,0) branch in the || condition was dead code — on GCC 10+ HEDLEY_HAS_BUILTIN already fires. Fix: guard the HEDLEY_HAS_BUILTIN path so GCC 10+ only uses the builtin when glibc >= 2.25 is confirmed. Non-glibc platforms and older glibc fall through to the portable inline fallback (roundf + fabsf), which requires no libm symbols beyond what every C platform provides. Clang is unaffected: it lowers __builtin_roundeven to llvm.roundeven.* intrinsics which are always emitted inline (no libm dependency), so the GCC guard does not apply there. Both simde_math_roundeven (double) and simde_math_roundevenf (float) are fixed identically. Fixes link failure observed on OpenBSD/GCC building VVenC with bundled SIMDE: fraunhoferhhi/vvenc#680
2baf39d to
fd3d458
Compare
GCC 10+ lowers __builtin_roundeven/__builtin_roundevenf to libm calls (roundeven/roundevenf), which are C23 additions only available in glibc >= 2.25. On non-glibc platforms (musl, OpenBSD, Alpine Linux, MinGW) these symbols don't exist, causing linker errors. Fix: restrict the HEDLEY_HAS_BUILTIN path so GCC 10+ only uses the builtin when glibc >= 2.25 is confirmed. Non-glibc systems and older glibc versions fall through to the portable inline fallback. Clang is unaffected because it lowers to LLVM intrinsics emitted inline. Mirrors fix from simd-everywhere/simde#1398. https://claude.ai/code/session_01QVvBbKu7xsm96hQUgvqd9E
Add a Cirrus CI task that builds and tests SIMDE on Alpine Linux (musl libc) with GCC and SIMDE_NO_NATIVE disabled. This combination catches link errors caused by __builtin_roundeven being lowered to a roundeven() libm call on GCC 10+: musl lacks roundeven() (C23), so the linker error surfaces immediately. SIMDE_NO_NATIVE ensures the scalar path is taken even on x86-64 with SSE4.1, preventing GCC from inlining the builtin as a ROUNDSD instruction and masking the issue. Suggested during review of simd-everywhere#1398.
Add a Cirrus CI task that builds and tests SIMDE on Alpine Linux (musl libc) with GCC and SIMDE_NO_NATIVE disabled. This combination catches link errors caused by __builtin_roundeven being lowered to a roundeven() libm call on GCC 10+: musl lacks roundeven() (C23), so the linker error surfaces immediately. SIMDE_NO_NATIVE ensures the scalar path is taken even on x86-64 with SSE4.1, preventing GCC from inlining the builtin as a ROUNDSD instruction and masking the issue. Suggested during review of simd-everywhere#1398.
Problem
roundeven()androundevenf()are C23 functions added to glibc 2.25 (2017).On non-glibc platforms (OpenBSD, musl, Alpine Linux, etc.) they are absent.
The original condition in
simde-math.h:On GCC 10+,
__has_builtin(introduced in GCC 10) returns true for__builtin_roundeven(also introduced in GCC 10), so theHEDLEY_HAS_BUILTINbranch is taken. GCC lowers this builtin to aroundeven()libm call when the hardware has no native instruction.On platforms without
roundevenin libm, this causes a link error:This was observed building VVenC (which bundles SIMDE) on OpenBSD with
GCC 13: fraunhoferhhi/vvenc#680
Note:
HEDLEY_GCC_VERSION_CHECK(10,0,0)in the original||branchwas dead code — on GCC 10+ the
HEDLEY_HAS_BUILTINbranch alwaysfires first.
Fix
Guard the
HEDLEY_HAS_BUILTINpath so that GCC 10+ only uses thebuiltin when glibc ≥ 2.25 is present. Non-glibc platforms and old
glibc fall through to the portable inline fallback.
Why Clang is unaffected: Clang lowers
__builtin_roundeventollvm.roundeven.*intrinsics, which LLVM always emits inline (no libmdependency). The
!HEDLEY_GCC_VERSION_CHECK(10,0,0)branch stays openfor Clang on all platforms.
Why glibc 2.25:
roundeven()was added in glibc 2.25 (2017).Checking only
defined(__GLIBC__)would allow glibc 2.24 and earlier,where the symbol is also absent.
Both
simde_math_roundeven(double, line 1271) andsimde_math_roundevenf(float, line 1293) are fixed identically.