2013-03-17 76 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

相关问题