模拟AVX-512掩码指令

时间:2017-03-06 01:56:44

标签: c++ gcc sse avx512

根据文档,支持来自gcc 4.9指令集的AVX-512,但我有gcc 4.8。我目前有这样的代码用于总结一块内存(它保证小于256字节,所以没有溢出问题):

__mm128i sum = _mm_add_epi16(sum, _mm_cvtepu8_epi16(*(__m128i *) &mem));

现在,查看文档,如果我们有剩下的四个字节,我可以使用:

__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));

(注意,__mmask8的类型似乎没有记录在我能找到的任何地方,所以我猜...)

但是,_mm_mask_cvtepu8_epi16AVX-512指令,有没有办法复制它?我试过了:

mm_mullo_epi16(_mm_set_epi16(0,0,0,0,1,1,1,1),
               _mm_cvtepu8_epi16(*(__m128i *) &mem));

然而,有一个缓存失速,所以直接for (int i = 0; i < remaining_bytes; i++) sum += mem[i];提供了更好的性能。

1 个答案:

答案 0 :(得分:2)

因为我碰巧遇到了这个问题,但如果仍然存在问题,它仍然没有得到答案......

对于您的示例问题,您已走上正确的轨道。

  • 乘法是一个相对较慢的操作,因此您应该避免使用_mm_mullo_epi16。使用_mm_and_si128代替按位AND是一个更快的操作,例如_mm_and_si128(_mm_cvtepu8_epi16(*(__m128i *) &mem), _mm_set_epi32(0, 0, -1, -1))
  • 我不确定缓存停顿是什么意思,但是如果内存访问是瓶颈,并且编译器不能将上面的常量放入寄存器,那么可以使用像{ {1}}不需要任何额外的寄存器/内存负载。移位可能比AND慢。
  • 如果它总是8个字节,则可以使用_mm_srli_si128(vector, 8)
  • 如果剩余数字不是固定数量的元素(例如,对于某些任意_mm_move_epi64,您有n%16个字节),这些都不能解决问题。 请注意,AVX-512也没有真正解决它。如果你需要处理这种情况,你可以有一个面具表和AND表,具体取决于剩下的是什么,例如: n
  • _mm_and_si128(vector, masks[n & 0xf])只关心向量的低半部分,所以你的例子有些令人困惑 - 也就是说,你不需要掩盖任何东西,因为后来的元素完全被忽略了)

在更通用的层面上,掩码操作实际上只是嵌入式_mm_mask_cvtepu8_epi16(或等效的)。对于归零惯用语,可以使用_mm_blend_epi16 / _mm_and_si128轻松模拟它们,如上所示。