From a8a15170a1e131693f73f5b2595286bb8b5e0cd7 Mon Sep 17 00:00:00 2001 From: vera-rubin <322284620+vera-rubin@users.noreply.github.com> Date: Tue, 13 Oct 2026 03:44:01 +0000 Subject: [PATCH 1/2] Fix SSE packed vector stores for GCC strict-aliasing optimizer The SSE paths of XMStoreColor, XMStoreHalf2 (F16C), XMStoreShortN2, XMStoreShort2 and the 32-bit DEC/BYTE packed stores wrote integer storage through a float* with _mm_store_ss. With strict aliasing (GCC -O2) the compiler may assume that store does not modify the integer member, so a later read of .c or .v can return the previous value. Assign the low 32-bit lane via _mm_cvtsi128_si32 instead, as XMVectorGetIntX already does. This still compiles to a single movd store. --- Inc/DirectXPackedVector.inl | 66 ++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/Inc/DirectXPackedVector.inl b/Inc/DirectXPackedVector.inl index 4771649..4d7541d 100644 --- a/Inc/DirectXPackedVector.inl +++ b/Inc/DirectXPackedVector.inl @@ -2040,7 +2040,7 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreColor(XMCOLOR* pDestinatio // Mash to bytes vInt = _mm_packus_epi16(vInt, vInt); // Store the color - _mm_store_ss(reinterpret_cast(&pDestination->c), _mm_castsi128_ps(vInt)); + pDestination->c = static_cast(_mm_cvtsi128_si32(vInt)); #endif } @@ -2049,8 +2049,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreHalf2(XMHALF2* pDestinatio { assert(pDestination); #if defined(_XM_F16C_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) - __m128i V1 = _mm_cvtps_ph(V, _MM_FROUND_TO_NEAREST_INT); - _mm_store_ss(reinterpret_cast(pDestination), _mm_castsi128_ps(V1)); + __m128i V1 = _mm_cvtps_ph(V, _MM_FROUND_TO_NEAREST_INT); + pDestination->v = static_cast(_mm_cvtsi128_si32(V1)); #else pDestination->x = XMConvertFloatToHalf(XMVectorGetX(V)); pDestination->y = XMConvertFloatToHalf(XMVectorGetY(V)); @@ -2086,7 +2086,7 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreShortN2(XMSHORTN2* pDestin vResult = _mm_mul_ps(vResult, g_ShortMax); __m128i vResulti = _mm_cvtps_epi32(vResult); vResulti = _mm_packs_epi32(vResulti, vResulti); - _mm_store_ss(reinterpret_cast(&pDestination->x), _mm_castsi128_ps(vResulti)); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -2118,8 +2118,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreShort2(XMSHORT2* pDestinat // Convert to int with rounding __m128i vInt = _mm_cvtps_epi32(vResult); // Pack the ints into shorts - vInt = _mm_packs_epi32(vInt, vInt); - _mm_store_ss(reinterpret_cast(&pDestination->x), _mm_castsi128_ps(vInt)); + vInt = _mm_packs_epi32(vInt, vInt); + pDestination->v = static_cast(_mm_cvtsi128_si32(vInt)); #endif } @@ -2851,13 +2851,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreXDecN4(XMXDECN4* pDestinat __m128i vResultw = _mm_and_si128(vResulti, g_XMMaskW); vResulti = _mm_add_epi32(vResulti, vResultw); // Do a horizontal or of all 4 entries - vResult = XM_PERMUTE_PS(_mm_castsi128_ps(vResulti), _MM_SHUFFLE(0, 3, 2, 1)); - vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); - vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); - vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); - vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); - vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResult = XM_PERMUTE_PS(_mm_castsi128_ps(vResulti), _MM_SHUFFLE(0, 3, 2, 1)); + vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); + vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); + vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); + vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); + vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -2932,8 +2932,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreXDec4(XMXDEC4* pDestinatio // Perform a single bit left shift on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3004,8 +3004,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUDecN4(XMUDECN4* pDestinat // Perform a left shift by one bit on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3069,8 +3069,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUDecN4_XR(XMUDECN4* pDesti // Perform a left shift by one bit on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3128,8 +3128,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUDec4(XMUDEC4* pDestinatio // Perform a left shift by one bit on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3199,8 +3199,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreDecN4(XMDECN4* pDestinatio // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3252,8 +3252,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreDec4(XMDEC4* pDestination, // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3315,8 +3315,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUByteN4(XMUBYTEN4* pDestin // Perform a single bit left shift to fix y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3365,8 +3365,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUByte4(XMUBYTE4* pDestinat // Perform a single bit left shift to fix y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3415,8 +3415,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreByteN4(XMBYTEN4* pDestinat // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } @@ -3463,8 +3463,8 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreByte4(XMBYTE4* pDestinatio // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); - _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); + vResulti = _mm_or_si128(vResulti, vResulti2); + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif } From 91c099129da3308f61bd58136e5f78b44a164778 Mon Sep 17 00:00:00 2001 From: vera-rubin <322284620+vera-rubin@users.noreply.github.com> Date: Thu, 15 Oct 2026 07:24:03 +0000 Subject: [PATCH 2/2] Keep the _mm_store_ss pattern for MSVC in SSE packed vector stores MSVC tolerates this type pun, so keep the existing _mm_store_ss store under #ifdef _MSC_VER and use the _mm_cvtsi128_si32 assignment only for other compilers. The MSVC code path is now unchanged from main. --- Inc/DirectXPackedVector.inl | 98 ++++++++++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/Inc/DirectXPackedVector.inl b/Inc/DirectXPackedVector.inl index 4d7541d..220c442 100644 --- a/Inc/DirectXPackedVector.inl +++ b/Inc/DirectXPackedVector.inl @@ -2040,8 +2040,12 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreColor(XMCOLOR* pDestinatio // Mash to bytes vInt = _mm_packus_epi16(vInt, vInt); // Store the color +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->c), _mm_castsi128_ps(vInt)); +#else pDestination->c = static_cast(_mm_cvtsi128_si32(vInt)); #endif +#endif } //------------------------------------------------------------------------------ @@ -2049,8 +2053,12 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreHalf2(XMHALF2* pDestinatio { assert(pDestination); #if defined(_XM_F16C_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) - __m128i V1 = _mm_cvtps_ph(V, _MM_FROUND_TO_NEAREST_INT); + __m128i V1 = _mm_cvtps_ph(V, _MM_FROUND_TO_NEAREST_INT); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(pDestination), _mm_castsi128_ps(V1)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(V1)); +#endif #else pDestination->x = XMConvertFloatToHalf(XMVectorGetX(V)); pDestination->y = XMConvertFloatToHalf(XMVectorGetY(V)); @@ -2086,7 +2094,11 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreShortN2(XMSHORTN2* pDestin vResult = _mm_mul_ps(vResult, g_ShortMax); __m128i vResulti = _mm_cvtps_epi32(vResult); vResulti = _mm_packs_epi32(vResulti, vResulti); - pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->x), _mm_castsi128_ps(vResulti)); +#else + pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); +#endif #endif } @@ -2118,9 +2130,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreShort2(XMSHORT2* pDestinat // Convert to int with rounding __m128i vInt = _mm_cvtps_epi32(vResult); // Pack the ints into shorts - vInt = _mm_packs_epi32(vInt, vInt); + vInt = _mm_packs_epi32(vInt, vInt); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->x), _mm_castsi128_ps(vInt)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vInt)); #endif +#endif } //------------------------------------------------------------------------------ @@ -2851,14 +2867,18 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreXDecN4(XMXDECN4* pDestinat __m128i vResultw = _mm_and_si128(vResulti, g_XMMaskW); vResulti = _mm_add_epi32(vResulti, vResultw); // Do a horizontal or of all 4 entries - vResult = XM_PERMUTE_PS(_mm_castsi128_ps(vResulti), _MM_SHUFFLE(0, 3, 2, 1)); - vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); - vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); - vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); - vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); - vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); + vResult = XM_PERMUTE_PS(_mm_castsi128_ps(vResulti), _MM_SHUFFLE(0, 3, 2, 1)); + vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); + vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); + vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); + vResult = XM_PERMUTE_PS(vResult, _MM_SHUFFLE(0, 3, 2, 1)); + vResulti = _mm_or_si128(vResulti, _mm_castps_si128(vResult)); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -2932,9 +2952,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreXDec4(XMXDEC4* pDestinatio // Perform a single bit left shift on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } #ifdef __GNUC__ @@ -3004,9 +3028,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUDecN4(XMUDECN4* pDestinat // Perform a left shift by one bit on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -3069,9 +3097,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUDecN4_XR(XMUDECN4* pDesti // Perform a left shift by one bit on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -3128,9 +3160,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUDec4(XMUDEC4* pDestinatio // Perform a left shift by one bit on y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -3199,9 +3235,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreDecN4(XMDECN4* pDestinatio // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -3252,9 +3292,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreDec4(XMDEC4* pDestination, // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } #ifdef __GNUC__ @@ -3315,9 +3359,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUByteN4(XMUBYTEN4* pDestin // Perform a single bit left shift to fix y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -3365,9 +3413,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreUByte4(XMUBYTE4* pDestinat // Perform a single bit left shift to fix y|w vResulti2 = _mm_add_epi32(vResulti2, vResulti2); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -3415,9 +3467,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreByteN4(XMBYTEN4* pDestinat // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------ @@ -3463,9 +3519,13 @@ _Use_decl_annotations_ inline void XM_CALLCONV XMStoreByte4(XMBYTE4* pDestinatio // Move Z to the x position vResulti2 = _mm_shuffle_epi32(vResulti, _MM_SHUFFLE(1, 1, 1, 1)); // i = x|y|z|w - vResulti = _mm_or_si128(vResulti, vResulti2); + vResulti = _mm_or_si128(vResulti, vResulti2); +#ifdef _MSC_VER + _mm_store_ss(reinterpret_cast(&pDestination->v), _mm_castsi128_ps(vResulti)); +#else pDestination->v = static_cast(_mm_cvtsi128_si32(vResulti)); #endif +#endif } //------------------------------------------------------------------------------