hel*_*922 14
比基于Agner Fog解决方案的 Marat解决方案(可能)更快的方式:
而不是分裂高/低,分裂奇数/偶数.这有一个额外的好处,它适用于纯SSE2,而不是需要SSE4.1(对OP没有用,但对一些人来说是一个很好的额外奖励).如果你有AVX2,我还添加了一个优化.从技术上讲,AVX2优化仅适用于SSE2内在函数,但它比左移右解更慢.
__m128i mullo_epi8(__m128i a, __m128i b)
{
// unpack and multiply
__m128i dst_even = _mm_mullo_epi16(a, b);
__m128i dst_odd = _mm_mullo_epi16(_mm_srli_epi16(a, 8),_mm_srli_epi16(b, 8));
// repack
#ifdef __AVX2__
// only faster if have access to VPBROADCASTW
return _mm_or_si128(_mm_slli_epi16(dst_odd, 8), _mm_and_si128(dst_even, _mm_set1_epi16(0xFF)));
#else
return _mm_or_si128(_mm_slli_epi16(dst_odd, 8), _mm_srli_epi16(_mm_slli_epi16(dst_even,8), 8));
#endif
}
Run Code Online (Sandbox Code Playgroud)
Agner使用blendv_epi8内在的SSE4.1支持.
编辑:
有趣的是,在进行了更多的反汇编工作(使用优化的构建版本)之后,至少我的两个实现被编译为完全相同的东西.针对"常春藤桥"(AVX)的示例反汇编.
vpmullw xmm2,xmm0,xmm1
vpsrlw xmm0,xmm0,0x8
vpsrlw xmm1,xmm1,0x8
vpmullw xmm0,xmm0,xmm1
vpsllw xmm0,xmm0,0x8
vpand xmm1,xmm2,XMMWORD PTR [rip+0x281]
vpor xmm0,xmm0,xmm1
Run Code Online (Sandbox Code Playgroud)
它使用"AVX2优化"版本和预编译的128位xmm常量.仅使用SSE2支持进行编译会产生类似的结果(尽管使用SSE2指令).我怀疑Agner Fog的原始解决方案可能会针对同样的事情进行优化(如果不这样做会很疯狂).不知道Marat的原始解决方案如何在优化的构建中进行比较,但对于我来说,对于所有x86 simd扩展而言,比SSE2更新的所有x86 simd扩展都非常好.
Mar*_*han 11
MMX/SSE/AVX中没有8位乘法.但是,您可以使用16位乘法模拟8位乘法内在,如下所示:
inline __m128i _mm_mullo_epi8(__m128i a, __m128i b)
{
__m128i zero = _mm_setzero_si128();
__m128i Alo = _mm_cvtepu8_epi16(a);
__m128i Ahi = _mm_unpackhi_epi8(a, zero);
__m128i Blo = _mm_cvtepu8_epi16(b);
__m128i Bhi = _mm_unpackhi_epi8(b, zero);
__m128i Clo = _mm_mullo_epi16(Alo, Blo);
__m128i Chi = _mm_mullo_epi16(Ahi, Bhi);
__m128i maskLo = _mm_set_epi8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 14, 12, 10, 8, 6, 4, 2, 0);
__m128i maskHi = _mm_set_epi8(14, 12, 10, 8, 6, 4, 2, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
__m128i C = _mm_or_si128(_mm_shuffle_epi8(Clo, maskLo), _mm_shuffle_epi8(Chi, maskHi));
return C;
}
Run Code Online (Sandbox Code Playgroud)
唯一的8位SSE乘法指令是PMADDUBSW(SSSE3及更高版本,C/C++内在函数:_mm_maddubs_epi16).此相乘16×8位无符号的 16×8位值签名值,然后求和相邻对,得到8×16位有符号的结果.如果你不能使用这个相当专业的指令,那么你需要解压缩到16位向量对并使用常规的16位乘法指令.显然这意味着至少有2倍的吞吐量命中,所以如果可能的话,使用8位乘法.