如何更新矢量化程序集(AVX)中的数组?

How to update an array in vectorized assembly(AVX)?

inline void addition(double * x, const double * vx,uint32_t size){
    /*for (uint32_t i=0;i<size;++i){
        x[i] = x[i] + vx[i];
    }*/
    __asm__ __volatile__ (
    "1: \n\t" 

    "vmovupd    -32(%0), %%ymm1\n\t"
    "vmovupd    (%0), %%ymm0\n\t"
    "vaddpd     -32(%1), %%ymm0, %%ymm0\n\t"
    "vaddpd     (%1), %%ymm1, %%ymm1\n\t"

    "vmovupd    %%ymm0, -32(%0)\n\t"
    "vmovupd    %%ymm1, (%0)\n\t"

    "addq   8, %0\n\t"
    "addq   8, %1\n\t"

    "addl   $-8, %2\n\t"
    "jne    1b"
        : 
        : "r" (x),"r"(vx),"r"(size)
        : "ymm0", "ymm1"
    );
}

我现在正在练习汇编(AVX指令)所以我用内联汇编写了上面这段代码来替换原来函数(被注释​​掉)中的c代码。编译过程成功,但是当我尝试 运行 程序时,发生错误:Bus error: 10 对这个错误有什么想法吗?我不知道这里出了什么问题。编译器版本是 clang 602.0.53。谢谢!

内联汇编是一个复杂的野兽,如果你只是想练习 AVX 汇编,请使用一个单独的 asm 文件,你不必忍受编译器。作为交换,您需要遵守调用约定。

您的约束有一些问题。例如,您在不通知编译器的情况下更改了所有输入寄存器,这可能会在编译器生成的代码的其他地方导致各种奇怪的问题。出于明显的原因,您还需要指定 memory 破坏。

此外,学习使用调试器,这样您就可以找到问题的确切原因并修复您自己的代码。

如果做不到这一点,请至少评论您的代码,以便我们了解您的意图。在这种情况下,我特别不解为什么在数组前使用-32偏移地址。我想你想要 +32 在那里。使用两个每个 32 字节的 avx 寄存器,您当然需要将指针提前 64 而不是 128。此外,您在初始加载中交换了 ymm0ymm1

这段代码对我来说似乎工作正常:

#include <stdio.h>
#include <stdint.h>

inline void addition(double * x, const double * vx,uint32_t size){
    /*for (uint32_t i=0;i<size;++i){
        x[i] = x[i] + vx[i];
    }*/
    __asm__ __volatile__ (
    "1: \n\t" 

    "vmovupd    32(%0), %%ymm0\n\t"
    "vmovupd    (%0), %%ymm1\n\t"
    "vaddpd     32(%1), %%ymm0, %%ymm0\n\t"
    "vaddpd     (%1), %%ymm1, %%ymm1\n\t"

    "vmovupd    %%ymm0, 32(%0)\n\t"
    "vmovupd    %%ymm1, (%0)\n\t"

    "addq   , %0\n\t"
    "addq   , %1\n\t"

    "addl   $-8, %2\n\t"
    "jne    1b"
        : "+r" (x),"+r"(vx),"+r"(size)
        :
        : "ymm0", "ymm1", "memory"
    );
}

int main()
{
    double x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    double vx[] = { 9, 10, 11, 12, 13, 14, 15, 16 };
    int i;
    addition(x, vx, 8);
    for(i = 0; i < 8; i++) printf("%g ", x[i]);
    putchar('\n');
    return 0;
}