如何更新矢量化程序集(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。此外,您在初始加载中交换了 ymm0
和 ymm1
。
这段代码对我来说似乎工作正常:
#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;
}
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。此外,您在初始加载中交换了 ymm0
和 ymm1
。
这段代码对我来说似乎工作正常:
#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;
}