Подтвердить что ты не робот

Каким образом можно использовать разные версии SSE-встроенных функций в GCC?

Я задам свой вопрос, представив пример. Теперь у меня есть функция с именем do_something().

Он имеет три версии: do_something(), do_something_sse3() и do_something_sse4(). Когда моя программа запустится, она обнаружит функцию ЦП (см., Поддерживает ли она SSE3 или SSE4) и соответствующим образом вызовет одну из трех версий.

Проблема заключается в следующем:. Когда я создаю свою программу с помощью GCC, мне нужно установить -msse4 для do_something_sse4() для компиляции (например, для заголовочного файла <smmintrin.h> для включения).

Однако, если я устанавливаю -msse4, то gcc разрешено использовать инструкции SSE4, а некоторые встроенные в do_something_sse3() также переводятся в некоторые инструкции SSE4. Поэтому, если моя программа работает на процессоре, который поддерживает только SSE3 (но не SSE4), он вызывает "незаконную инструкцию" при вызовах do_something_sse3().

Может быть, у меня плохая практика. Не могли бы вы дать некоторые предложения? Спасибо.

4b9b3361

Ответ 1

Я думаю, что Mystical tip отлично, но если вы действительно хотите сделать это в одном файле, вы можете использовать pragmas, например:

#pragma GCC target("sse4.1")

Требуется GCC 4.4, AFAIR.

Ответ 2

Я думаю, вы хотите создать так называемый "диспетчер процессора". У меня есть один рабочий (насколько я знаю) для GCC, но у меня нет работы с Visual Studio.
диспетчер cpu для визуальной студии для AVX и SSE

Я бы просмотрел векторный класс Agner Fog и файл dispatch_example.cpp http://www.agner.org/optimize/#vectorclass

g++ -O3 -msse2   -c dispatch_example.cpp -od2.o
g++ -O3 -msse4.1 -c dispatch_example.cpp -od5.o
g++ -O3 -mavx    -c dispatch_example.cpp -od8.o
g++ -O3 -msse2      instrset_detect.cpp d2.o d5.o d8.o

Ответ 3

Вот пример компиляции отдельного объектного файла для каждого параметра оптимизации: http://notabs.org/lfsr/software/index.htm

Но даже этот метод выходит из строя, когда используется оптимизация времени gcc link (-flto). Итак, как можно создать единый исполняемый файл с полной оптимизацией для разных процессоров? Единственное решение, которое я могу найти, это использовать директивы include, чтобы файлы C отображались как единый блок компиляции, так что -flto не требуется. Вот пример использования этого метода: http://notabs.org/blcutil/index.htm

Ответ 4

Если вы используете GCC 4.9 или выше на машине i686 или x86_64, вы должны использовать встроенные функции независимо от ваших параметров -march=XXX и -mXXX. Вы можете написать свой do_something() соответственно:

void do_something()
{
    byte temp[18];

    if (HasSSE2())
    {
        const __m128i i = _mm_loadu_si128((const __m128i*)(ptr));
        ...
    }
    else if (HasSSSE3())
    {
        const __m128i MASK = _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3);
        _mm_storeu_si128(reinterpret_cast<__m128i*>(temp),
           _mm_shuffle_epi8(_mm_loadu_si128((const __m128i*)(ptr)), MASK));
    }
    else
    {
        // Do the byte swap/endian reversal manually
        ...
    }
}

Вы должны поставить HasSSE2(), HasSSSE3() и друзей. Также см. Intrinsics для получения информации о CPUID?.

Также см. GCC Issue 57202 - Пожалуйста, создайте заголовки intrinsics, такие как immintrin.h, без флагов компилятора. Но я не считаю, что эта функция работает. Я регулярно сталкиваюсь с сбоями компиляции, потому что GCC не делает доступными встроенные функции.