Отключить функции AVX2 на процессорах, отличных от Haswell

Я написал код AVX2 для запуска на процессоре Haswell i7. Та же самая кодовая база также используется на процессорах не-Haswell, где тот же код должен быть заменен их эквивалентами SSE. Мне было интересно, есть ли способ для компилятора игнорировать инструкции AVX2 на не-Haswell процессорах. Мне нужно что-то вроде:

public void useSSEorAVX(...){
    IF (compiler directive detected AVX2)
        AVX2 code (this part is ready)
    ELSE
        SSE code  (this part is also ready)
    }
}

Прямо сейчас я комментирую связанный код перед компиляцией, но должен быть более эффективный способ сделать это. Я использую Ubuntu и GCC. Спасибо за вашу помощь.

2 ответа

Решение

Если вы просто хотите сделать это во время компиляции, вы можете сделать это:

#ifdef __AVX2__
    // AVX2 code
#elif __SSE__
    // SSE code
#else
    // scalar code
#endif

Обратите внимание, что когда вы компилируете с gcc -mavx2 ... затем __AVX2__ определяется автоматически. Аналогично для __SSE__, (Обратите также внимание, что вы можете проверить, что предопределено вашим компилятором для любого данного переключения командной строки, используя заклинание gcc -dM -E -mavx2 - < /dev/null.)

Если вы хотите выполнить диспетчеризацию во время выполнения, тогда это немного сложнее.

Я не думаю, что это хорошая идея сделать отдельный исполняемый файл, если вам не нужно. В вашем случае вы можете сделать диспетчер процессора. Я сделал это недавно для GCC и Visual studio.

Давайте предположим, что у вас есть функция с именем product для SSE и AVX. Вы помещаете версию SSE в файл product_SSE.cpp, а версию AVX2 - в файл product_AVX2.cpp. Вы компилируете каждый отдельно (например, с -msse2 а также -mavx2). Затем сделайте такой модуль:

extern "C" void product_SSE(float *a, float *b, float *c, int n);
extern "C" void product_AVX2(float *a, float *b, float *c, int n); 
           void product_dispatch(float *a, float *b, float *c, int n); 
void (*fp)(float* a, float *b, float *c, int n) = product_dispatch;

inline void product_dispatch(float *a, float *b, float *c, int n) {
    int iset = instrset_detect();
    if(iset==8) {
        fp = product_AVX2
    }
    else {
        fp = product_SSE
    }
    fp(a,b,c,n);
}

inline void product(float *a, float *b, float*c, int bs) {
    fp(a,b,c,n);
}

Вы компилируете этот модуль с нижним общим набором команд (например, с SSE2). Теперь, когда вы звоните продукт, он сначала звонит product_dispatch устанавливает указатель на функцию fpлибо product_AVX2 или же product_SSE а затем вызывает функцию из указателя функции. Второй раз звонишь productон прыгает прямо на product_AVX2или же product_SSE, Таким образом, вам не нужно иметь отдельный исполняемый файл.

Другие вопросы по тегам