Помощь GCC с авто-векторизацией

У меня есть шейдер, который мне нужно оптимизировать (с большим количеством векторных операций), и я экспериментирую с инструкциями SSE, чтобы лучше понять проблему.

У меня есть очень простой пример кода. С USE_SSE определить это использует явные SSE-свойства; без этого я надеюсь, что GCC сделает всю работу за меня. Авто-векторизация кажется немного привередливой, но я надеюсь, что это спасет меня от волос.

Компилятор и платформа: gcc 4.7.1 (tdm64), target x86_64-w64-mingw32 и Windows 7 на Ivy Bridge.

Вот тестовый код:

/*
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 тоже полезны, вот где будет работать настоящий код.

4

Решение

это LockLess статья о Авто-векторизация с gcc 4.7 Это лучшая статья, которую я когда-либо видел, и я потратил некоторое время на поиск хороших статей на подобные темы. У них также есть много других статьи что вы можете найти очень полезными на подобные темы, касающиеся всех способов разработки программного обеспечения низкого уровня.

7

Другие решения

Вот несколько советов, основанных на вашем коде для того, чтобы сделать автоматическую векторизацию gcc:

  • сделать петлю восходящей. Для векторизации GCC необходимо разделить цикл на 4 итерации, чтобы он поместился в регистр SSE XMM, длина которого составляет 128 бит. верхняя граница константного цикла поможет 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];
    }
    

КСТАТИ:

  • GCC также имеет флаги, чтобы помочь вам выяснить, был ли цикл векторизован. -ftree-vectorizer-verbose=2большее число будет иметь больше выходной информации, в настоящее время значение может быть 0,1,2,Вот это документация этого флага и некоторых других связанных флагов.
  • Будьте осторожны с выравниванием. Адрес массива должен быть выровнен, и компилятор не может знать, выровнен ли адрес без его запуска. Обычно, будет bus error если данные не выровнены. Вот это причина.
5

По вопросам рекламы [email protected]