2013-03-17 44 views
4

我有一個着色器,我需要優化(與大量的矢量操作),我正在試驗SSE指令,以便更好地瞭解問題。幫助海灣合作委員會與自動矢量化

我有一些非常簡單的示例代碼。使用USE_SSE定義它使用顯式的SSE內在函數;沒有它我希望GCC會爲我做這項工作。自動矢量化感覺有點挑剔,但我希望它能爲我節省一些頭髮。

編譯器和平臺是:gcc 4.7.1(tdm64),目標x86_64-w64-mingw32和Ivy Bridge上的Windows 7。

下面是測試代碼:

/* 
    Include all the SIMD intrinsics. 
*/ 
#ifdef USE_SSE 
#include <x86intrin.h> 
#endif 
#include <cstdio> 

#if defined(__GNUG__) || defined(__clang__) 
    /* GCC & CLANG */ 

    #define SSVEC_FINLINE __attribute__((always_inline)) 

#elif defined(_WIN32) && defined(MSC_VER) 
    /* MSVC. */ 

    #define SSVEC_FINLINE __forceinline 

#else 
#error Unsupported platform. 
#endif 


#ifdef USE_SSE 

    typedef __m128 vec4f; 

    inline void addvec4f(vec4f &a, vec4f const &b) 
    { 
     a = _mm_add_ps(a, b); 
    } 

#else 

    typedef float vec4f[4]; 

    inline void addvec4f(vec4f &a, vec4f const &b) 
    { 
     a[0] = a[0] + b[0]; 
     a[1] = a[1] + b[1]; 
     a[2] = a[2] + b[2]; 
     a[3] = a[3] + b[3]; 
    } 

#endif 

int main(int argc, char *argv[]) 
{ 
    int const count = 1e7; 

    #ifdef USE_SSE 
    printf("Using SSE.\n"); 
    #else 
    printf("Not using SSE.\n"); 
    #endif 

    vec4f data = {1.0f, 1.0f, 1.0f, 1.0f}; 

    for (int i = 0; i < count; ++i) 
    { 
     vec4f val = {0.1f, 0.1f, 0.1f, 0.1f}; 
     addvec4f(data, val); 
    } 

    float result[4] = {0}; 
    #ifdef USE_SSE 
    _mm_store_ps(result, data); 
    #else 
    result[0] = data[0]; 
    result[1] = data[1]; 
    result[2] = data[2]; 
    result[3] = data[3]; 
    #endif 

    printf("Result: %f %f %f %f\n", result[0], result[1], result[2], result[3]); 

    return 0; 
} 

這編譯:

g++ -O3 ssetest.cpp -o nossetest.exe 
g++ -O3 -DUSE_SSE ssetest.cpp -o ssetest.exe 
從明確的SSE版本

除了是有點快有輸出沒有什麼區別。

下面是循環中,第一次明確SSE大會:

.L3: 
subl $1, %eax 
addps %xmm1, %xmm0 
jne .L3 

它內聯的呼叫。不錯,或多或少只是直線上升_mm_add_ps

陣列版本:

.L3: 
subl $1, %eax 
addss %xmm0, %xmm1 
addss %xmm0, %xmm2 
addss %xmm0, %xmm3 
addss %xmm0, %xmm4 
jne .L3 

它使用SSE數學好的,但每個陣列成員上。不是真的好。

我的問題是,我該如何幫助GCC,以便它能更好地優化陣列版本vec4f

任何Linux特定的技巧也有幫助,這就是真正的代碼將運行的地方。

+0

注意,'float結果[4]'可能不會在堆棧上排列的16個字節的 - 它發生在這種情況下工作,或'_mm_store_ps'會發生故障。 – 2013-03-18 00:44:48

回答

6

LockLess文章Auto-vectorization with gcc 4.7下跌最好的文章中,我所見過的手和我花了一段時間尋找類似主題的好文章。他們也有很多其他的articles,你可能會發現在處理低級別軟件開發的所有方式的類似主題上非常有用。

+0

感謝您的鏈接,嘗試在這篇文章中的提示,但它似乎很難得到它自動矢量化正確。現在嘗試一個結構體,被迫是16字節對齊的,但我能做的最好的是4個'addss'指令。 – Skurmedel 2013-03-18 01:18:19

+1

@Skurmedel同意,當我更積極地擴展X86 wikibook的SSE部分時,我發現了這個和其他文章正在進行研究。你看看內在的東西嗎?我一直在尋找一些我有的內在材料,但我似乎無法再挖掘它了。 – 2013-03-19 02:17:39

5

這是根據你的代碼,使GCC自動向量化的一些技巧的工作原理:

  • 使環upbound一個const。爲了進行矢量化,GCC需要通過4次迭代來分割循環,以適應128位長度的SSE XMM寄存器。一個const循環上限將有助於GCC確保循環有很多迭代,並且矢量化是有利可圖的。
  • 刪除inline關鍵字。如果代碼被標記爲內聯,則GCC無法知道數組的起始點是否已對齊,而沒有將由-O3打開的程序間分析。

    如此,使你的代碼向量化,你addvec4f功能應修改如下:

    void addvec4f(vec4f &a, vec4f const &b) 
    { 
        int i = 0; 
        for(;i < 4; i++) 
         a[i] = a[i]+b[i]; 
    } 
    

BTW:

  • GCC也有標誌,以幫助您找出是否一個循環已經被矢量化了。 -ftree-vectorizer-verbose=2,較高的數字將具有更多的輸出信息,當前值可以是0,1,2Here是此標誌的文檔以及其他相關標誌。
  • 小心對齊。數組的地址應該對齊,並且編譯器無法知道地址是否對齊而不運行。通常,如果數據未對齊,將會有bus errorHere是原因。
+0

謝謝,會嘗試你的建議。 – Skurmedel 2013-03-19 18:51:31

相關問題