2 ms·
Whenever you need a lookup table with vectors, remember the instructions like _mm256_cvtepu8_epi32 or _mm256_cvtepi8_epi64 can zero extend or sign extend intege
by Const-me 4y ago
Whenever you need a lookup table with vectors, remember the instructions like _mm256_cvtepu8_epi32 or _mm256_cvtepi8_epi64 can zero extend or sign extend integer lanes, and they can load source directly from memory. The OP needs a vector with int32 lanes in [0..7] range, can use 1 byte per lane and expand to uint32_t while loading with _mm256_cvtepu8_epi32. Reduces table size by a factor of 4, at the cost of a single instruction.
Another thing, it’s possible to produce the desired vectors without RAM loads, with a couple of BMI2 instructions. Example in C++:
// Compress int32 lanes according to the mask
// The mask is expected to contain either 0 or UINT_MAX values
__m256i compress_epi32( __m256i val, __m256i mask )
{
uint32_t i32 = (uint32_t)_mm256_movemask_epi8( mask );
// Compress, using 4 bit numbers for lane indices
constexpr uint32_t identity = 0x76543210;
i32 = _pext_u32( identity, i32 );
// Expand 4-bit numbers into bytes
constexpr uint64_t expand = 0x0F0F0F0F0F0F0F0Full;
uint64_t i64 = _pdep_u64( (uint64_t)i32, expand );
// Move to SSE vector
__m128i vec = _mm_cvtsi64_si128( (int64_t)i64 );
// Expand bytes to uint32_t
__m256i perm = _mm256_cvtepu8_epi32( vec );
// Shuffle these elements
return _mm256_permutevar8x32_epi32( val, perm );
}
One downside, these BMI2 instructions are rather slow on Zen 2 and earlier AMD processors. AMD has fixed the performance in Zen 3.