我有一个avx 2(256位)SIMD字节向量,在前面和后面用零填充,如下所示:[0, 2, 3, ..., 4, 5, 0, 0, 0]。编译时不知道前面的零的数量。我如何有效地移位/旋转零,使其看起来像这样:[2, 3, 4, 5, ..., 0, 0, 0, 0]?
[0, 2, 3, ..., 4, 5, 0, 0, 0]
[2, 3, 4, 5, ..., 0, 0, 0, 0]
tyky79it1#
AVX 2无法执行粒度小于4字节的跨通道混洗。(在《冰湖》中)。如果你有那个,也许在面具上有vpcmpeqb/vpmovmskb/tzcnt,并将其作为偏移量从alignas(64) int8_t shuffles = {0,1,2,...,31, 0, 1, 2, ... 31};常量数组中加载一个32字节的窗口。这就是vpermb的shuffle控制向量。如果没有AVX-512 VBMI,尽管存储转发会暂停,但存储两次并跨两次执行未对齐的重载 * 可能 * 是有意义的。如果您需要在许多其他工作之间为一个向量执行此操作,这对吞吐量是有好处的,但如果在没有太多其他工作的循环中执行此操作,这就不太好了。Store-forwarding stalls don't pipeline with each other, but can pipeline with successful store-forwarding。因此,如果您只是偶尔需要一个向量,并且无序exec可以隐藏延迟,则无需向vpcmpeqb/tzcnt或lzcnt执行许多微操作即可获得加载偏移。
vpcmpeqb
vpmovmskb
tzcnt
alignas(64) int8_t shuffles = {0,1,2,...,31, 0, 1, 2, ... 31};
vpermb
pw9qyyiw2#
我不太理解关于_mm256_permutevar8x32_epi32的文档,但实际上,向恒等置换添加偏移量会进行旋转-这是您想要的(当您已经获得前导0的数量时)。
_mm256_permutevar8x32_epi32
__m256i rotate_i32(__m256i w, int offset) { __m256i identity = _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0); __m256i shuffle = _mm256_add_epi32(identity, _mm256_set1_epi32(offset)); return _mm256_permutevar8x32_epi32(w, shuffle); }
神箭在这里:https://godbolt.org/z/Kv8oxs6oY
(-1, -2, -3, -4, -5, -6, -7, -8) (-2, -3, -4, -5, -6, -7, -8, -1) (-3, -4, -5, -6, -7, -8, -1, -2) (-4, -5, -6, -7, -8, -1, -2, -3) (-5, -6, -7, -8, -1, -2, -3, -4) (-6, -7, -8, -1, -2, -3, -4, -5) (-7, -8, -1, -2, -3, -4, -5, -6) (-8, -1, -2, -3, -4, -5, -6, -7)
同样的技巧也适用于64位,但需要多次偏移2。
__m256i rotate_i64(__m256i w, int offset) { __m256i identity = _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0); __m256i shuffle = _mm256_add_epi32(identity, _mm256_set1_epi32(offset * 2)); return _mm256_permutevar8x32_epi32(w, shuffle); }
神箭:https://godbolt.org/z/85h6aWPsW输出量:
(-1, -2, -3, -4) (-2, -3, -4, -1) (-3, -4, -1, -2) (-4, -1, -2, -3)
2条答案
按热度按时间tyky79it1#
AVX 2无法执行粒度小于4字节的跨通道混洗。(在《冰湖》中)。如果你有那个,也许在面具上有
vpcmpeqb
/vpmovmskb
/tzcnt
,并将其作为偏移量从alignas(64) int8_t shuffles = {0,1,2,...,31, 0, 1, 2, ... 31};
常量数组中加载一个32字节的窗口。这就是vpermb
的shuffle控制向量。如果没有AVX-512 VBMI,尽管存储转发会暂停,但存储两次并跨两次执行未对齐的重载 * 可能 * 是有意义的。如果您需要在许多其他工作之间为一个向量执行此操作,这对吞吐量是有好处的,但如果在没有太多其他工作的循环中执行此操作,这就不太好了。
Store-forwarding stalls don't pipeline with each other, but can pipeline with successful store-forwarding。因此,如果您只是偶尔需要一个向量,并且无序exec可以隐藏延迟,则无需向vpcmpeqb/tzcnt或lzcnt执行许多微操作即可获得加载偏移。
pw9qyyiw2#
如果类型大于32位。
我不太理解关于
_mm256_permutevar8x32_epi32
的文档,但实际上,向恒等置换添加偏移量会进行旋转-这是您想要的(当您已经获得前导0的数量时)。神箭在这里:https://godbolt.org/z/Kv8oxs6oY
同样的技巧也适用于64位,但需要多次偏移2。
神箭:https://godbolt.org/z/85h6aWPsW
输出量: