我有以下循环:
float* s;
float* ap;
float* bp;
... // initialize s, ap, bp
for(size_t i=0;i<64;++i) {
s[i] = ap[i]+bp[i];
}
似乎是向量化的好人选。尽管启动了优化,但当我查看程序集输出时,clang (我使用的是Xcode)似乎没有将循环向量化:
LBB33_1: ## =>This Inner Loop Header: Depth=1
movss (%rax,%rsi,4), %xmm0 ## xmm0 = mem[0],zero,zero,zero
addss (%rcx,%rsi,4), %xmm0
movss %xmm0, (%rdx,%rsi,4)
Ltmp353:
incq %rsi
Ltmp354:
cmpq $64, %rsi
Ltmp355:
jne LBB33_1
如何获得clang/Xcode来矢量化这个简单的循环?
发布于 2019-04-05 18:32:13
使用非古代版本的clang/LLVM。Apple /LLVM与主线clang/LLVM不同,但它们有一个共同的代码库。
主线clang3.3和更新的自动矢量化循环在-O3
.-O2
**.** Clang3.4和更新版本的自动矢量化
如果没有restrict
,clang就会发出asm,以检查目标和两个源之间的重叠(返回到标量),因此您将从float *restrict s
获得更有效的asm。
#include <stdlib.h>
void add_float_good(float *restrict s, float *restrict ap, float *restrict bp)
{
for(size_t i=0;i<64;++i) {
s[i] = ap[i]+bp[i];
}
}
用最糟糕的索引寻址模式和循环开销将使用clang3.4-O3(在戈德波特编译器浏览器上)编译到这个简单的asm中,但至少它是向量化的。较新的clang喜欢展开,特别是在为最近的英特尔(如-march=skylake
)进行调优时。
# clang3.4 -O3
add_float_good:
xor eax, eax
.LBB0_1: # %vector.body
movups xmm0, xmmword ptr [rsi + 4*rax]
movups xmm1, xmmword ptr [rdx + 4*rax]
addps xmm1, xmm0
movups xmmword ptr [rdi + 4*rax], xmm1
add rax, 4
cmp rax, 64
jne .LBB0_1
ret
注意,如果没有AVX,它就不能为addps
使用内存源操作数,因为没有编译时对齐的保证。
clang8.0 -O3 -march=skylake完全使用YMM向量展开,就像gcc具有相同的选项。
发布于 2019-04-05 18:13:35
最好是使用“加速”来明确这一点。在这种情况下,vDSP_vadd会做到这一点。
https://stackoverflow.com/questions/55545231
复制