如何使用非立即输入进行类似于_mm_extract_epi8的操作?
How to make an operation similar to _mm_extract_epi8 with non-immediate input?
我想要的是使用可变标量索引从向量中提取值。
类似于 _mm_extract_epi8
/ _mm256_extract_epi8
但具有非即时输入。
(向量中有一些结果,找到给定索引的结果是真正的结果,其余的被丢弃)
到目前为止,最好的选择似乎是对 SSE
使用 _mm_shuffle_epi8
uint8_t extract_epu8var(__m128i val, int index) {
return (uint8_t)_mm_cvtsi128_si32(
_mm_shuffle_epi8(val, _mm_cvtsi32_si128(index)));
}
不幸的是,这对于 AVX 来说不能很好地扩展。 vpshufb
不会跨车道洗牌。有一个cross lane shuffle _mm256_permutevar8x32_epi32
,但是结果看起来很复杂:
uint8_t extract_epu8var(__m256i val, int index) {
int index_low = index & 0x3;
int index_high = (index >> 2);
return (uint8_t)(_mm256_cvtsi256_si32(_mm256_permutevar8x32_epi32(
val, _mm256_zextsi128_si256(_mm_cvtsi32_si128(index_high))))
>> (index_low << 3));
}
特别是,如果index
在一个GPR中,最简单的方法可能是将val
存储到内存中,然后movzx
将其存储到另一个GPR中。使用 C:
的示例实现
uint8_t extract_epu8var(__m256i val, int index) {
union {
__m256i m256;
uint8_t array[32];
} tmp;
tmp.m256 = val;
return tmp.array[index];
}
Godbolt 翻译(请注意,堆栈对齐会产生大量开销——如果您没有对齐的临时存储区域,您可以 vmovdqu
而不是 vmovdqa
):https://godbolt.org/z/Gj6Eadq9r
我想要的是使用可变标量索引从向量中提取值。
类似于 _mm_extract_epi8
/ _mm256_extract_epi8
但具有非即时输入。
(向量中有一些结果,找到给定索引的结果是真正的结果,其余的被丢弃)
到目前为止,最好的选择似乎是对 SSE
使用_mm_shuffle_epi8
uint8_t extract_epu8var(__m128i val, int index) {
return (uint8_t)_mm_cvtsi128_si32(
_mm_shuffle_epi8(val, _mm_cvtsi32_si128(index)));
}
不幸的是,这对于 AVX 来说不能很好地扩展。 vpshufb
不会跨车道洗牌。有一个cross lane shuffle _mm256_permutevar8x32_epi32
,但是结果看起来很复杂:
uint8_t extract_epu8var(__m256i val, int index) {
int index_low = index & 0x3;
int index_high = (index >> 2);
return (uint8_t)(_mm256_cvtsi256_si32(_mm256_permutevar8x32_epi32(
val, _mm256_zextsi128_si256(_mm_cvtsi32_si128(index_high))))
>> (index_low << 3));
}
特别是,如果index
在一个GPR中,最简单的方法可能是将val
存储到内存中,然后movzx
将其存储到另一个GPR中。使用 C:
uint8_t extract_epu8var(__m256i val, int index) {
union {
__m256i m256;
uint8_t array[32];
} tmp;
tmp.m256 = val;
return tmp.array[index];
}
Godbolt 翻译(请注意,堆栈对齐会产生大量开销——如果您没有对齐的临时存储区域,您可以 vmovdqu
而不是 vmovdqa
):https://godbolt.org/z/Gj6Eadq9r