根据文档,从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];可以提供更好的性能。

最佳答案

当我碰巧碰到这个问题时,如果这仍然是一个问题,它仍然没有得到答案...

对于示例问题,您处于正确的轨道。

  • Multiply是一个相对较慢的操作,因此应避免使用_mm_mullo_epi16。使用_mm_and_si128代替按位AND是一个更快的操作,例如_mm_and_si128(_mm_cvtepu8_epi16(*(__m128i *) &mem), _mm_set_epi32(0, 0, -1, -1))
  • 我不确定您所说的高速缓存停顿是什么意思,但是如果内存访问是一个瓶颈,并且编译器不会将上述常量放入寄存器中,则可以使用_mm_srli_si128(vector, 8)之类的东西,不需要任何内容​​。其他寄存器/存储器负载。移位可能比AND慢。
  • 如果始终为8个字节,则可以使用_mm_move_epi64
  • 如果剩余数量不是固定数量的元素(例如,您有n%16个字节用于某些任意n),则以上方法都无法解决。请注意,AVX-512也无法真正解决它。如果您需要处理这种情况,则可以使用一张掩码表和AND(取决于剩余),例如_mm_and_si128(vector, masks[n & 0xf])
  • (_mm_mask_cvtepu8_epi16只关心 vector 的下半部分,因此您的示例有些困惑-也就是说,您不需要掩盖任何东西,因为稍后的元素会被完全忽略)

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

    关于c++ - 模拟AVX-512掩码指令,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42616373/

  • 10-11 23:23