From 5787472a77fa800ab408fc84b9cdf744f46cc873 Mon Sep 17 00:00:00 2001 From: Jordan Peck Date: Fri, 16 Oct 2026 22:44:20 +0100 Subject: [PATCH] SSE2 int multiply: keep products in place for every compiler clang 23 no longer recognises the psrldq/pmuludq/pshufd/punpckldq sequence as a 32 bit multiply, so chained multiplies (e.g. hash * hash * constant) repack the lanes in between. Combining the even/odd pmuludq results in place with and/shift/or keeps the low 32 bits of each 64 bit lane where pmuludq reads them: a single multiply is still 6 instructions, a chained one needs no repacking. The in-place and/shift/or form is as fast or faster than the shuffle/unpack repack on MSVC 14.51/14.44 and GCC 16/13 too (FastNoise2 SSE2 benchmarks 0.985-0.993 of the previous time), so every compiler uses it. Integer results are identical. --- include/FastSIMD/ToolSet/x86/128/i32x4.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/FastSIMD/ToolSet/x86/128/i32x4.h b/include/FastSIMD/ToolSet/x86/128/i32x4.h index 44d3219..4e80bf1 100644 --- a/include/FastSIMD/ToolSet/x86/128/i32x4.h +++ b/include/FastSIMD/ToolSet/x86/128/i32x4.h @@ -44,9 +44,11 @@ namespace FS } else { + // Products stay in place in their 64 bit lanes: chained multiplies need no repacking in between, + // pmuludq only reads the low 32 bits of each 64 bit lane, which the and/shift/or leave in place __m128i mul20 = _mm_mul_epu32( native, rhs.native ); /* mul 2,0*/ - __m128i mul31 = _mm_mul_epu32( _mm_srli_si128( native, 4 ), _mm_srli_si128( rhs.native, 4 ) ); /* mul 3,1 */ - native = _mm_unpacklo_epi32( _mm_shuffle_epi32( mul20, _MM_SHUFFLE( 0, 0, 2, 0 ) ), _mm_shuffle_epi32( mul31, _MM_SHUFFLE( 0, 0, 2, 0 ) ) ); /* shuffle results to [63..0] and pack */ + __m128i mul31 = _mm_mul_epu32( _mm_shuffle_epi32( native, _MM_SHUFFLE( 3, 3, 1, 1 ) ), _mm_shuffle_epi32( rhs.native, _MM_SHUFFLE( 3, 3, 1, 1 ) ) ); /* mul 3,1 */ + native = _mm_or_si128( _mm_and_si128( mul20, _mm_set_epi32( 0, -1, 0, -1 ) ), _mm_slli_epi64( mul31, 32 ) ); } return *this; }