LLVM / Clang生成无用的指令

时间:2019-02-08 17:06:24

标签: c assembly compilation x86-64 llvm-clang

如果我编写这段代码:

void loop1(int N, double* R, double* A, double* B) {
    for (int i = 0; i < N; i += 1) {
        R[i] = A[i] + B[i];
    }
}

Clang(-O3)生成以下x64 ASM作为循环(Compiler Explorer)展开版本的一部分:

.LBB0_14:
    movupd  xmm0, xmmword ptr [rdx + 8*rax]
    movupd  xmm1, xmmword ptr [rdx + 8*rax + 16]
    movupd  xmm2, xmmword ptr [rcx + 8*rax]
    addpd   xmm2, xmm0
    movupd  xmm0, xmmword ptr [rcx + 8*rax + 16]
    addpd   xmm0, xmm1
    movupd  xmmword ptr [rsi + 8*rax], xmm2
    movupd  xmmword ptr [rsi + 8*rax + 16], xmm0

rdxrcx握住我的输入指针(A / B),rsi是输出(R),并且rax是一个偏移量计数器。因此,它一次加载两对输入/输出,使用SIMD指令添加它们,然后将它们写入输出-到目前为止,一切都很好。

如果我改写以下内容:

void loop2(int N, double* R, double* A, double* B) {
    for (int i = 0; i < N; i += 2) {
        R[i] = A[i] + B[i];
        R[i + 1] = A[i + 1] + B[i + 1];
    }
}

LLVM生成以下(Compiler Explorer):

.LBB0_13:
    movupd  xmm0, xmmword ptr [rdx + 8*rdi]
    movupd  xmm1, xmmword ptr [rdx + 8*rdi + 16]
    movupd  xmm2, xmmword ptr [rcx + 8*rdi]
    addpd   xmm2, xmm0
    movupd  xmm0, xmmword ptr [rcx + 8*rdi + 16]
    addpd   xmm0, xmm1

    movapd  xmm1, xmm2
    unpckhpd        xmm1, xmm0      # xmm1 = xmm1[1],xmm0[1]
    unpcklpd        xmm2, xmm0      # xmm2 = xmm2[0],xmm0[0]
    movapd  xmm0, xmm2
    unpcklpd        xmm0, xmm1      # xmm0 = xmm0[0],xmm1[0]
    unpckhpd        xmm2, xmm1      # xmm2 = xmm2[1],xmm1[1]

    movupd  xmmword ptr [rsi + 8*rdi + 16], xmm2
    movupd  xmmword ptr [rsi + 8*rdi], xmm0

为清楚起见添加了空格,因为中间的部分带有unpckhpd等,这使我感到困惑。据我所知,这6条指令的整体效果只是交换xmm0xmm2,这似乎是在浪费时间。

知道为什么要这么做吗?有办法阻止它吗? :p


EDIT :我为loop2()编辑了ASM,以删除所有相似的块(并在后续的写操作中在寄存器之间交换),并且它似乎可以正常运行并且与loop1()(快40%)

0 个答案:

没有答案