如何让clang来矢量化一个简单的循环?

问题描述 投票:1回答:2

我有以下循环:

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对这个简单的循环进行矢量化?

c clang vectorization compiler-optimization sse
2个回答
6
投票

使用非古老版本的clang / LLVM。 Apple clang / 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];
    }
}

使用最差的索引寻址模式和循环开销将with clang3.4 -O3 (on the Godbolt compiler explorer)编译为这个简单的asm,但至少它是矢量化的。较新的铿锵喜欢展开,特别是在调整最近的英特尔(例如-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具有相同的选项。


0
投票

最好使用Accelerate来明确这一点。在这种情况下,vDSP_vadd将完成这一操作。

© www.soinside.com 2019 - 2024. All rights reserved.