From fa76357d336ed44e3f2c5250a85c81b965f60946 Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Tue, 4 Aug 2026 11:11:04 -0700 Subject: [PATCH] Fix __FINITE_MATH_ONLY__ guard to test the value, not definedness XMVectorIsNaN, XMVector2IsNaN, XMVector3IsNaN and XMVector4IsNaN each guard a scalar fallback with: #if defined(__clang__) && defined(__FINITE_MATH_ONLY__) but clang defines __FINITE_MATH_ONLY__ unconditionally -- 0 by default, and 1 only under -ffast-math / -ffinite-math-only (clang-cl /fp:fast). The guard is therefore always true under clang, so the fallback is compiled into every clang build instead of only finite-math ones. Two consequences: - The fallback calls unqualified isnan(), so any clang target whose C++ library does not declare isnan() fails to compile. This is how the bug surfaced. - Where it does compile, a single vector compare is replaced by a store, four scalar tests and a reassemble. Test the macro's value instead. Verified with clang-cl that the guard is now false at the default /fp:precise and still true under /fp:fast. Affects both the NEON and SSE paths of all four functions (8 sites). --- Inc/DirectXMathVector.inl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Inc/DirectXMathVector.inl b/Inc/DirectXMathVector.inl index 20bbab1d..761cf677 100644 --- a/Inc/DirectXMathVector.inl +++ b/Inc/DirectXMathVector.inl @@ -2186,7 +2186,7 @@ inline XMVECTOR XM_CALLCONV XMVectorIsNaN(FXMVECTOR V) noexcept return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ XMVECTORU32 vResult = { { { isnan(vgetq_lane_f32(V, 0)) ? 0xFFFFFFFFU : 0, isnan(vgetq_lane_f32(V, 1)) ? 0xFFFFFFFFU : 0, @@ -2200,7 +2200,7 @@ inline XMVECTOR XM_CALLCONV XMVectorIsNaN(FXMVECTOR V) noexcept return vreinterpretq_f32_u32(vmvnq_u32(vTempNan)); #endif #elif defined(_XM_SSE_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ XM_ALIGNED_DATA(16) float tmp[4]; _mm_store_ps(tmp, V); XMVECTORU32 vResult = { { { @@ -6653,7 +6653,7 @@ inline bool XM_CALLCONV XMVector2IsNaN(FXMVECTOR V) noexcept return (XMISNAN(V.vector4_f32[0]) || XMISNAN(V.vector4_f32[1])); #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ return isnan(vgetq_lane_f32(V, 0)) || isnan(vgetq_lane_f32(V, 1)); #else float32x2_t VL = vget_low_f32(V); @@ -6663,7 +6663,7 @@ inline bool XM_CALLCONV XMVector2IsNaN(FXMVECTOR V) noexcept return (vget_lane_u64(vreinterpret_u64_u32(vTempNan), 0) != 0xFFFFFFFFFFFFFFFFU); #endif #elif defined(_XM_SSE_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ XM_ALIGNED_DATA(16) float tmp[4]; _mm_store_ps(tmp, V); return isnan(tmp[0]) || isnan(tmp[1]); @@ -9418,7 +9418,7 @@ inline bool XM_CALLCONV XMVector3IsNaN(FXMVECTOR V) noexcept XMISNAN(V.vector4_f32[2])); #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ return isnan(vgetq_lane_f32(V, 0)) || isnan(vgetq_lane_f32(V, 1)) || isnan(vgetq_lane_f32(V, 2)); #else // Test against itself. NaN is always not equal @@ -9429,7 +9429,7 @@ inline bool XM_CALLCONV XMVector3IsNaN(FXMVECTOR V) noexcept return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) != 0xFFFFFFU); #endif #elif defined(_XM_SSE_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ XM_ALIGNED_DATA(16) float tmp[4]; _mm_store_ps(tmp, V); return isnan(tmp[0]) || isnan(tmp[1]) || isnan(tmp[2]); @@ -13309,7 +13309,7 @@ inline bool XM_CALLCONV XMVector4IsNaN(FXMVECTOR V) noexcept XMISNAN(V.vector4_f32[2]) || XMISNAN(V.vector4_f32[3])); #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ return isnan(vgetq_lane_f32(V, 0)) || isnan(vgetq_lane_f32(V, 1)) || isnan(vgetq_lane_f32(V, 2)) || isnan(vgetq_lane_f32(V, 3)); #else // Test against itself. NaN is always not equal @@ -13320,7 +13320,7 @@ inline bool XM_CALLCONV XMVector4IsNaN(FXMVECTOR V) noexcept return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) != 0xFFFFFFFFU); #endif #elif defined(_XM_SSE_INTRINSICS_) -#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) +#if defined(__clang__) && __FINITE_MATH_ONLY__ XM_ALIGNED_DATA(16) float tmp[4]; _mm_store_ps(tmp, V); return isnan(tmp[0]) || isnan(tmp[1]) || isnan(tmp[2]) || isnan(tmp[3]);