我正在尝试编写一些相当快速的分量向量加法代码。我正在使用(我相信是有符号的)64 位整数。
函数是
void addRq (int64_t* a, const int64_t* b, const int32_t dim, const int64_t q) {
for(int i = 0; i < dim; i++) {
a[i] = (a[i]+b[i])%q; // LINE1
}
}
我正在编译icc -std=gnu99 -O3
(icc,以便我稍后可以使用 SVML)在 IvyBridge(SSE4.2 和 AVX,但不是 AVX2)上。
我的基线是删除%q
来自 LINE1。 100 个(迭代)函数调用dim=11221184
需要 1.6 秒。 ICC 自动矢量化 SSE 代码;伟大的。
不过我真的很想做模块化添加。随着%q
,ICC 不会自动矢量化代码,并且运行时间为 11.8 秒(!)。即使忽略之前尝试的自动矢量化,这仍然看起来有些过分。
由于我没有 AVX2,因此使用 SSE 进行矢量化需要 SVML,这也许就是 ICC 不自动矢量化的原因。无论如何,这是我对内部循环进行矢量化的尝试:
__m128i qs = _mm_set1_epi64x(q);
for(int i = 0; i < dim; i+=2) {
__m128i xs = _mm_load_si128((const __m128i*)(a+i));
__m128i ys = _mm_load_si128((const __m128i*)(b+i));
__m128i zs = _mm_add_epi64(xs,ys);
zs = _mm_rem_epi64(zs,qs);
_mm_store_si128((__m128i*)(a+i),zs);
}
主循环的汇编是:
..B3.4: # Preds ..B3.2 ..B3.12
movdqa (%r12,%r15,8), %xmm0 #59.22
movdqa %xmm8, %xmm1 #60.14
paddq (%r14,%r15,8), %xmm0 #59.22
call __svml_i64rem2 #61.9
movdqa %xmm0, (%r12,%r15,8) #61.36
addq $2, %r15 #56.30
cmpq %r13, %r15 #56.24
jl ..B3.4 # Prob 82% #56.24
因此代码正在按预期进行矢量化。我知道由于 SVML,我可能无法获得 2 倍的加速,但代码运行时间为 12.5 秒,比根本没有矢量化的情况慢!这真的是这里能做到的最好的事情吗?