函数为:
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)。
我的基准是从 LINE1 中删除 %q
。对于 dim=11221184
的100次(迭代)函数调用需要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秒,比没有任何向量化时要慢!这真的是在这里可以做到的最好吗?