@@ -193,22 +193,45 @@ static inline __m128i _mm_shuffle_epi8(__m128i a, __m128i b) {
193193 return vreinterpretq_s64_u8 (vqtbl1q_u8 (tbl , idx ));
194194}
195195static inline __m128i _mm_shuffle_epi32 (__m128i a , const int imm ) {
196- uint32_t t [4 ];
197- uint32_t r [4 ];
198- vst1q_u32 (t , vreinterpretq_u32_s64 (a ));
199- r [0 ] = t [imm & 3 ];
200- r [1 ] = t [(imm >> 2 ) & 3 ];
201- r [2 ] = t [(imm >> 4 ) & 3 ];
202- r [3 ] = t [(imm >> 6 ) & 3 ];
203- return vreinterpretq_s64_u32 (vld1q_u32 (r ));
196+ /* Permute the four 32-bit lanes. `imm` is a compile-time constant at every
197+ * call site, so the broadcast fast paths fold away and the general case
198+ * builds a constant byte index that compiles to a single TBL. */
199+ uint32x4_t v = vreinterpretq_u32_s64 (a );
200+ if (imm == 0x00 )
201+ return vreinterpretq_s64_u32 (vdupq_laneq_u32 (v , 0 ));
202+ if (imm == 0x55 )
203+ return vreinterpretq_s64_u32 (vdupq_laneq_u32 (v , 1 ));
204+ if (imm == 0xAA )
205+ return vreinterpretq_s64_u32 (vdupq_laneq_u32 (v , 2 ));
206+ if (imm == 0xFF )
207+ return vreinterpretq_s64_u32 (vdupq_laneq_u32 (v , 3 ));
208+ {
209+ const uint8_t b0 = (uint8_t )((imm & 3 ) * 4 );
210+ const uint8_t b1 = (uint8_t )(((imm >> 2 ) & 3 ) * 4 );
211+ const uint8_t b2 = (uint8_t )(((imm >> 4 ) & 3 ) * 4 );
212+ const uint8_t b3 = (uint8_t )(((imm >> 6 ) & 3 ) * 4 );
213+ const uint8x16_t idx = {
214+ b0 , (uint8_t )(b0 + 1 ), (uint8_t )(b0 + 2 ), (uint8_t )(b0 + 3 ),
215+ b1 , (uint8_t )(b1 + 1 ), (uint8_t )(b1 + 2 ), (uint8_t )(b1 + 3 ),
216+ b2 , (uint8_t )(b2 + 1 ), (uint8_t )(b2 + 2 ), (uint8_t )(b2 + 3 ),
217+ b3 , (uint8_t )(b3 + 1 ), (uint8_t )(b3 + 2 ), (uint8_t )(b3 + 3 )};
218+ return vreinterpretq_s64_u8 (vqtbl1q_u8 (vreinterpretq_u8_s64 (a ), idx ));
219+ }
204220}
205221static inline __m128i _mm_blend_epi16 (__m128i a , __m128i b , const int imm ) {
206- uint16_t m [8 ];
207- int i ;
208- for (i = 0 ; i < 8 ; i ++ )
209- m [i ] = ((imm >> i ) & 1 ) ? (uint16_t )0xFFFF : (uint16_t )0 ;
210- return vreinterpretq_s64_u16 (vbslq_u16 (vld1q_u16 (m ),
211- vreinterpretq_u16_s64 (b ),
222+ /* Per-16-bit-lane select from `a` (0) or `b` (1). `imm` is constant at every
223+ * call site, so this compound-literal mask folds to a constant vector load
224+ * feeding a single BSL, with no stack round-trip. */
225+ const uint16x8_t mask = {
226+ (imm & 0x01 ) ? (uint16_t )0xFFFF : (uint16_t )0 ,
227+ (imm & 0x02 ) ? (uint16_t )0xFFFF : (uint16_t )0 ,
228+ (imm & 0x04 ) ? (uint16_t )0xFFFF : (uint16_t )0 ,
229+ (imm & 0x08 ) ? (uint16_t )0xFFFF : (uint16_t )0 ,
230+ (imm & 0x10 ) ? (uint16_t )0xFFFF : (uint16_t )0 ,
231+ (imm & 0x20 ) ? (uint16_t )0xFFFF : (uint16_t )0 ,
232+ (imm & 0x40 ) ? (uint16_t )0xFFFF : (uint16_t )0 ,
233+ (imm & 0x80 ) ? (uint16_t )0xFFFF : (uint16_t )0 };
234+ return vreinterpretq_s64_u16 (vbslq_u16 (mask , vreinterpretq_u16_s64 (b ),
212235 vreinterpretq_u16_s64 (a )));
213236}
214237
0 commit comments