C++ 模拟AVX-512掩码指令
根据文档,支持AVX-512指令集上的C++ 模拟AVX-512掩码指令,c++,gcc,sse,avx512,C++,Gcc,Sse,Avx512,根据文档,支持AVX-512指令集上的GCC4.9,但我有GCC4.8。我目前有这样的代码,用于对内存块进行求和(保证小于256字节,因此无需担心溢出): 现在,查看文档,如果我们还有,比如说,四个字节,我可以使用: __mm128i sum = _mm_add_epi16(sum, _mm_mask_cvtepu8_epi16(_mm_set1_epi16(0),
GCC4.9
,但我有GCC4.8
。我目前有这样的代码,用于对内存块进行求和(保证小于256字节,因此无需担心溢出):
现在,查看文档,如果我们还有,比如说,四个字节,我可以使用:
__mm128i sum = _mm_add_epi16(sum,
_mm_mask_cvtepu8_epi16(_mm_set1_epi16(0),
(__mmask8)_mm_set_epi16(0,0,0,0,1,1,1,1),
*(__m128i *) &mem));
(注意,\uuu mmask8
的类型似乎在我能找到的任何地方都没有记录,所以我猜……)
但是,\u mm\u mask\u cvtepu8\u epi16
是一条AVX-512
指令,那么有没有办法复制它?我试过:
mm_mullo_epi16(_mm_set_epi16(0,0,0,0,1,1,1,1),
_mm_cvtepu8_epi16(*(__m128i *) &mem));
然而,有一个缓存暂停,所以只有(inti=0;i<剩余的_字节;i++)sum+=mem[i]代码>提供了更好的性能。因为我碰巧遇到了这个问题,它仍然没有得到答案,如果这仍然是一个问题的话 对于您的示例问题,您的思路是正确的
- 乘法运算相对较慢,因此应避免使用
。使用\u mm\u mullo\u epi16
而不是按位使用,这是一种更快的操作,例如\u-mm\u和\u-si128
\u-mm\u和\u-si128(\u-mm\u-cvtepu8\u-epi16(*(\u-m128i*)&mem),\u-mm\u-set\u-epi32(0,0,-1,-1))
- 我不知道你说的缓存暂停是什么意思,但是如果内存访问是一个瓶颈,并且编译器不会将上面的常量放入寄存器,那么可以使用类似于
的东西,它不需要任何额外的寄存器/内存加载。换档可能比和慢\u mm\u srli\u si128(vector,8)
- 如果始终为8字节,则可以使用
\u mm\u move\u epi64
- 如果剩余的数量不是固定数量的元素(例如,对于某些任意的
,您有n
字节),则所有这些都无法解决这种情况。请注意,AVX-512也不能真正解决这个问题。如果您需要处理这种情况,您可以有一个掩码表,并且取决于剩余的内容,例如n%16
\u mm\u和\u si128(向量,掩码[n&0xf])
- (
只关心向量的下半部分,因此您的示例有些混乱-也就是说,您不需要屏蔽任何内容,因为后面的元素完全被忽略)\u mm\u mask\u cvtepu8\u epi16
在更一般的层面上,掩码操作实际上只是一个嵌入的
\u mm\u blend\u epi16
(或等效)。对于归零习惯用法,可以很容易地用\u mm\u和_si128
/\u mm\u和not_si128
来模拟它们,如上所示。我不清楚您想要什么。您是否有AVX512硬件,但不支持编译器?并不是说128b(例如\u mm_mask\u cvtepu8\u epi16
)和256b mask操作需要AVX-512VL
,而KNL没有。你想要一个只支持SSE的解决方案吗?@Zboson,是的,我现在无法轻松升级编译器。简单的for
循环没有什么特别的错误,但我只是想知道是否有更好的方法,因为实际的循环体比求和要复杂一些-我有一个圆,正在计算(左、右)和(上、下)两半之间的相对权重。你有什么AVX512硬件?你的硬件到底是什么?@KenY-N:你的CPU是一个Haswell,它有AVX2,所以你可以使用AVX2屏蔽负载,例如,如果这有帮助的话?AVX512可以解决这个问题。你可以做\uuu mask32=(uint32\u t)-1UL>>((32字节左)和31
,这将编译成整数移位和kmov
。当然,你也可以使用各种技术在AVX2中生成掩码。看到好的一点,我没有想到。谢谢你的更正!
mm_mullo_epi16(_mm_set_epi16(0,0,0,0,1,1,1,1),
_mm_cvtepu8_epi16(*(__m128i *) &mem));