anu*_*nup 5 c optimization sse simd sse2
elma并且elmc都是unsigned long数组.所以是res1和res2.
unsigned long simdstore[2];
__m128i *p, simda, simdb, simdc;
p = (__m128i *) simdstore;
for (i = 0; i < _polylen; i++)
{
u1 = (elma[i] >> l) & 15;
u2 = (elmc[i] >> l) & 15;
for (k = 0; k < 20; k++)
{
//res1[i + k] ^= _mulpre1[u1][k];
//res2[i + k] ^= _mulpre2[u2][k];
simda = _mm_set_epi64x (_mulpre2[u2][k], _mulpre1[u1][k]);
simdb = _mm_set_epi64x (res2[i + k], res1[i + k]);
simdc = _mm_xor_si128 (simda, simdb);
_mm_store_si128 (p, simdc);
res1[i + k] = simdstore[0];
res2[i + k] = simdstore[1];
}
}
Run Code Online (Sandbox Code Playgroud)
在for循环中包括元素的XOR的非simd和simd版本.第二个for循环中的前两行执行显式XOR,而其余的执行相同操作的simd版本.
从外部调用此循环数百次,因此优化此循环将有助于缩短总计算时间.
问题是simd代码的运行速度比标量代码慢很多倍.
编辑:完成部分展开
__m128i *p1, *p2, *p3, *p4;
p1 = (__m128i *) simdstore1;
p2 = (__m128i *) simdstore2;
p3 = (__m128i *) simdstore3;
p4 = (__m128i *) simdstore4;
for (i = 0; i < 20; i++)
{
u1 = (elma[i] >> l) & 15;
u2 = (elmc[i] >> l) & 15;
for (k = 0; k < 20; k = k + 4)
{
simda1 = _mm_set_epi64x (_mulpre2[u2][k], _mulpre1[u1][k]);
simda2 = _mm_set_epi64x (_mulpre2[u2][k + 1], _mulpre1[u1][k + 1]);
simda3 = _mm_set_epi64x (_mulpre2[u2][k + 2], _mulpre1[u1][k + 2]);
simda4 = _mm_set_epi64x (_mulpre2[u2][k + 3], _mulpre1[u1][k + 3]);
simdb1 = _mm_set_epi64x (res2[i + k], res1[i + k]);
simdb2 = _mm_set_epi64x (res2[i + k + 1], res1[i + k + 1]);
simdb3 = _mm_set_epi64x (res2[i + k + 2], res1[i + k + 2]);
simdb4 = _mm_set_epi64x (res2[i + k + 3], res1[i + k + 3]);
simdc1 = _mm_xor_si128 (simda1, simdb1);
simdc2 = _mm_xor_si128 (simda2, simdb2);
simdc3 = _mm_xor_si128 (simda3, simdb3);
simdc4 = _mm_xor_si128 (simda4, simdb4);
_mm_store_si128 (p1, simdc1);
_mm_store_si128 (p2, simdc2);
_mm_store_si128 (p3, simdc3);
_mm_store_si128 (p4, simdc4);
res1[i + k]= simdstore1[0];
res2[i + k]= simdstore1[1];
res1[i + k + 1]= simdstore2[0];
res2[i + k + 1]= simdstore2[1];
res1[i + k + 2]= simdstore3[0];
res2[i + k + 2]= simdstore3[1];
res1[i + k + 3]= simdstore4[0];
res2[i + k + 3]= simdstore4[1];
}
}
Run Code Online (Sandbox Code Playgroud)
但是,结果并没有太大变化; 它仍然需要标量代码的两倍.
免责声明:我来自PowerPC背景,所以我在这里说的可能是完全的h .. 但是,由于您尝试立即访问结果,因此停止了矢量管道.
最好将所有内容保存在矢量管道中.只要你从vector到int或float进行任何类型的转换,或者将结果存储到内存中,你就会停滞不前.
处理SSE或VMX时的最佳操作模式是:加载,处理,存储.将数据加载到向量寄存器中,执行所有向量处理,然后将其存储到内存中.
我建议:保留几个__m128i寄存器,多次展开循环,然后存储它.
编辑:另外,如果您展开,如果按16个字节对齐RES1和RES2,你可以直接在内存中存储你的结果,而通过这个simdstore间接,这可能是一个LHS和其他摊位去.
编辑:忘了显而易见.如果您的polylen通常很大,请不要忘记在每次迭代时都执行数据缓存预取.
相对于正在执行的加载和存储数量,您在这里做的计算很少,因此您几乎看不到 SIMD 的好处。在这种情况下,您可能会发现使用标量代码更有用,特别是如果您有一个可以在 64 位模式下使用的 x86-64 CPU。这将减少加载和存储的数量,这些是当前性能的主要因素。
(注:你应该不是。展开循环,特别是如果你使用酷睿2或更高版本)