通过自动矢量化帮助GCC

Sku*_*del 4 c++ gcc sse mingw vectorization

我有一个着色器,我需要优化(有很多向量操作),我正在尝试SSE指令,以便更好地理解问题.

我有一些非常简单的示例代码.使用USE_SSE定义它使用显式SSE内在函数; 没有它,我希望海湾合作委员会能为我做这项工作.自动矢量化感觉有点挑剔,但我希望它能为我节省一些头发.

编译器和平台是: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;
}
Run Code Online (Sandbox Code Playgroud)

这是编译的:

g++ -O3 ssetest.cpp -o nossetest.exe
g++ -O3 -DUSE_SSE ssetest.cpp -o ssetest.exe
Run Code Online (Sandbox Code Playgroud)

除了明确的SSE版本更快一点之外,输出没有区别.

这是循环的程序集,第一个显式SSE:

.L3:
subl    $1, %eax
addps   %xmm1, %xmm0
jne .L3
Run Code Online (Sandbox Code Playgroud)

它内联了这个电话.很好,或多或少只是直线上升_mm_add_ps.

阵列版本:

.L3:
subl    $1, %eax
addss   %xmm0, %xmm1
addss   %xmm0, %xmm2
addss   %xmm0, %xmm3
addss   %xmm0, %xmm4
jne .L3
Run Code Online (Sandbox Code Playgroud)

它正在使用SSE数学,但在每个数组成员上.不是很理想.

我的问题是,我如何帮助GCC以便更好地优化阵列版本vec4f

任何特定于Linux的提示也很有用,这就是真正的代码运行的地方.

Sha*_*our 7

LockLess文章自动矢量用gcc 4.7是倒手是我所见过的最好的文章,我已经花了一边寻找类似主题的好文章.他们还有许多其他文章,你可能会发现它们在处理低级软件开发的所有方式的类似主题上非常有用.


Kun*_*ing 5

以下是基于您的代码使gcc自动矢量化工作的一些提示:

  • 使loop-upbound成为const.要进行向量化,GCC需要将循环分为4次迭代,以适应SSE XMM寄存器,即128位长度.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];
    }
    
    Run Code Online (Sandbox Code Playgroud)

BTW:

  • GCC还有标志来帮助您找出循环是否已被矢量化.-ftree-vectorizer-verbose=2,更高数量将有更多的输出信息,当前值可以是0,1,2.是该标志的文档,以及其他一些相关的标志.
  • 小心对齐.数组的地址应该是对齐的,并且编译器无法在不运行的情况下知道地址是否对齐.通常,bus error如果数据未对齐,则会有.就是原因.