2016-02-08 22 views
-3
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 $128, %0\n\t" 
    "addq $128, %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)中的数组?

+0

也许你可以问问*铛*生成(从C代码)为您汇编代码,并与您的版本进行比较? –

+0

@ringø除了一些标签不同且寄存器被指定外,它几乎是一样的。 – PLNewbie

+0

你的问题不是关于C,而是汇编。 – Olaf

回答

4

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

你有一些约束问题。例如,你在不告诉编译器的情况下改变你的所有输入寄存器,并且在编译器生成的代码的其他地方会导致各种奇怪的问题。您还需要指定memory clobber,原因很明显。

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

如果没有,至少要评论你的代码,以便我们能够弄清楚你的意图。在这种情况下,我特别疑惑你为什么在数组之前使用-32偏移量来解决问题。我想你在那里想要+32。使用两个avx寄存器(每个为32字节),您当然需要将指针前移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 $64, %0\n\t" 
    "addq $64, %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; 
} 
+0

非常感谢!我将不胜感激,如果你能给我一个链接到一个很好的学习lldb调试器的源码。:) – PLNewbie

+1

我是你的upvote。只是想观察到@PLNewbie(或阅读器),鉴于示例代码将只正常工作,如果'size'是8的倍数,并且必须是> = 8 –

+0

@PLNewbie:参见[86维基标签](http://stackoverflow.com/tags/x86/info)(我刚刚更新了一些与内联asm无关的东西)。它有一个关于为什么GNU C inline asm是学习asm最难的方法的说明。在asm中编写整个函数比较容易,或者使用intrinsics(然后查看编译器输出以确保它不会被吸引)。 –