优化从 AVX2 寄存器中提取 64 位值
Posted
技术标签:
【中文标题】优化从 AVX2 寄存器中提取 64 位值【英文标题】:Optimize extraction of 64 bit value from AVX2 register 【发布时间】:2014-01-13 00:55:18 【问题描述】:我尝试从 __m256i 寄存器中提取 64 位。 我当前的提取函数示例:
byte 31 16 15 0
byte_result_vec 000D 000C 000B 000A 000H 000G 000F 000E
_mm256_packs_epi32 -> 0D0C 0B0A 0D0C 0B0A 0H0G 0F0E 0H0G 0F0E
_mm256_packus_epi16 -> DCBA DCBA DCBA DCBA HGFE HGFE HGFE HGFE
^^^^ ^^^^
_mm256_castsi256_si128 -> HGFE HGFE HGFE HGFE
_mm256_extracti128_si256 -> DCBA DCBA DCBA DCBA
_mm_cvtsi128_si32(byte_result_vec1) -> ABCD
_mm_cvtsi128_si32(byte_result_vec2) -> EFGH
以下代码将 4x8 位移动到寄存器位置 0-3,而不是提取 32 位。
byte_result_vec = _mm256_packs_epi32(byte_result_vec, byte_result_vec);
byte_result_vec = _mm256_packus_epi16(byte_result_vec, byte_result_vec);
__m128i byte_result_vec1 = _mm256_castsi256_si128(byte_result_vec);
__m128i byte_result_vec2 = _mm256_extracti128_si256(byte_result_vec,1);
const int res1 = _mm_cvtsi128_si32(byte_result_vec1);
const int res2 = _mm_cvtsi128_si32(byte_result_vec2);
result_array[j] = res1;
result_array[j+1] = res2;
代码运行正常,但速度很慢。 看起来将 res1 和 res2 复制到 result_array 需要的时间最多。 有办法优化吗?
【问题讨论】:
【参考方案1】:可能这个变种会更快
/* byte_result_vec 000H 000G 000F 000E 000D 000C 000B 000A */
const __m256i shuffle_mask = _mm256_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1);
/* abcdefgh 0000 0000 HGFE 0000 0000 0000 0000 DCBA */
const __m256i abcdefgh = _mm256_shuffle_epi8(byte_result_vec, shuffle_mask);
/* abcd 0000 0000 0000 DCBA */
const __m128i abcd = _mm256_castsi256_si128(abcdefgh);
/* efgh 0000 0000 HGFE 0000 */
const __m128i efgh = _mm256_extracti128_si256(abcdefgh, 1);
_mm_storel_epi64((__m128i*)&result_array[j], _mm_or_si128(abcd, efgh));
【讨论】:
我刚刚发现还有一个额外的优化机会:可以将_mm256_castsi256_si128
+ _mm256_extracti128_si256
+ _mm_or_si128
替换为单个_mm256_permutevar8x32_epi32
以实现另一个延迟周期。
你能告诉我_mm256_castsi256_si128
和_mm256_castsf256_si128
之间的区别吗?第一个需要 AVX2,第二个只需要 AVX。为什么要使用_mm256_castsi256_si128
?
_mm256_castsi256_si128
是无操作的,只需要AVX
。类似地,其他强制转换是无操作的,它们仅在参数/结果类型上有所不同。
对不起,我问错问题了。我的意思是_mm256_extractf128_si256
和_mm256_extracti128_si256
之间有什么区别。我知道这些强制转换只是为了让编译器高兴。我的意思是***.com/questions/25684454/…
英特尔 CPU 传统上具有用于整数和浮点寄存器的单独寄存器文件和数据路径。因此,VEXTRACTI128
可能在 SIMD 内核的整数部分实现并连接到整数 SIMD 寄存器文件,VEXTRACTF128
- 在浮点部分实现并连接到 FP SIMD 寄存器文件。因此,如果您将 VEXTRACTI128
与浮点运算产生的数据一起使用(因此寄存器驻留在 FP 文件中),则在 SIMD 内核的各个部分之间移动数据可能会有几个周期的延迟。以上是关于优化从 AVX2 寄存器中提取 64 位值的主要内容,如果未能解决你的问题,请参考以下文章
AVX2:AVX 寄存器中 8 位元素的 CountTrailingZeros