我有一个着色器,我需要优化(有很多向量操作),我正在尝试使用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;
}
编译时使用:
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 :(得分:7)
关于Auto-vectorization with gcc 4.7的这篇LockLess
文章是我见过的最好的文章,我花了一段时间寻找有关类似主题的好文章。他们还有很多其他的articles,你可能会发现它们在处理低级软件开发的各种方式时非常有用。
答案 1 :(得分:5)
以下是基于您的代码使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];
}
顺便说一句: