2017-03-06 149 views
0

根据说明文件,从gcc 4.9开始支持AVX-512指令集,但是我有gcc 4.8。目前,我有这样的代码用于加的内存块(它的保证是小于256个字节,所以没有溢出后顾之忧):模拟AVX-512屏蔽指令

__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_epi16是一个AVX-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];了更好的性能。

+0

我不清楚你在做什么。你有AVX512硬件,但不是一个编译器来支持?并不是128b(例如'_mm_mask_cvtepu8_epi16')和256b掩码操作需要KNL没有的“AVX-512VL”。你想要一个SSE唯一的解决方案? –

+0

'for(int i = 0; i

+0

@Zboson,是的,我现在无法轻易升级编译器。简单的'for'循环没有什么特别的错,但我只是想知道是否有更好的方法,因为实际的循环体比复杂一点更复杂 - 我有一个圆并且计算(左侧和右侧)和(顶部和底部)一半。 –

回答

2

正如我正好碰到这个问题绊倒,它仍然没有得到答案,如果这仍然是一个问题...

对于您的问题,例如,你在正确的轨道上。

  • 乘法是一个相对较慢的操作,所以你应该避免使用_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)这样的东西, t需要任何额外的寄存器/存储器负载。换档可能比AND更慢。
  • 如果它总是8个字节,则可以使用_mm_move_epi64
  • 这一切都不解决的情况下,如果剩余数目不是元素的固定数量(例如你有一些任意nn%16字节)。 请注意,AVX-512也不能真正解决它。如果你需要处理这种情况,你可以有一个掩码和AND的表,这取决于剩下的内容,例如, _mm_and_si128(vector, masks[n & 0xf])
  • _mm_mask_cvtepu8_epi16只关心载体的低一半,所以你的例子是有点混乱 - 也就是说,你不需要掩饰任何东西,因为后面的元素被完全忽略安韦)

在一个更通用的级别,掩码操作实际上只是一个嵌入式_mm_blend_epi16(或等效)。对于习惯用法的调零,可以使用_mm_and_si128/_mm_andnot_si128轻松地进行仿真,如上所示。

+1

AVX512确实可以解决这个问题。你可以做'__mask32 =(uint32_t)-1UL >>((32-bytes_left)&31',它会编译成一个整数移位和一个'kmov'。当然你也可以在AVX2中生成一个掩码,使用各种技术。看到https://stackoverflow.com/questions/34306933/vectorizing-with-unaligned-buffers-using-vmaskmovps-generating-a-mask-from-am –

+0

好点,没有想过这件事。谢谢你的纠正! – zinga