2016-02-08 36 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(然後查看編譯器輸出以確保它不會被吸引)。 –