Zeroupper приводит к неверным результатам - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть следующий код внутри цикла for

    dataInt = _mm_loadu_si128((__m128i *) (&x[i]));
    __m256i val_unpacked = _mm256_cvtepi16_epi32(dataInt);
    __m256 converted = _mm256_cvtepi32_ps(val_unpacked);

    converted = _mm256_div_ps(converted, _mm256_set1_ps(max_val));

    _mm256_storeu_ps(&y[i], converted);
    _mm256_zeroupper();

В основном он просто конвертирует вектор int16 в число с плавающей точкой в ​​диапазоне [-1,1] (max_val является константной переменной и равен numeric_limit :: max).

Я использую компилятор mingw с версией posix thread 7.2

Когда я компилирую программу без оптимизации, она работает просто отлично, но когда я включаю оптимизацию (у меня нет контроля надотдельные оптимизации, это внутри проекта, над которым я работаю, но он должен использовать lvl оптимизации -O3), я начинаю получать неправильные результаты.

Проблема в инструкции zeroupper.Когда я удаляю его в режиме с оптимизациями, он снова дает правильные результаты.

По-видимому, оптимизация не учитывает размещение инструкции zeroupper и вызывает ее где-то в середине цикла, а не в самом конце,таким образом отбрасывая полезные данные.Возможно ли что-то подобное?Я не мог найти никакого обсуждения по этой теме в Интернете.

РЕДАКТИРОВАТЬ: я извлек код.Выглядит это так:

#include <iostream>
#include <limits>
#include <immintrin.h>
#include <xmmintrin.h>  
 int  __attribute__ ((__target__ ("avx2,sse4.2"))) main(){

/*volatile*/ float max_val = static_cast<float> (std::numeric_limits<int16_t>::max());

__m128i dataInt;
int runs = 32;
int16_t source[32];
float target[32];
int i = 0;
for (; i < 32; ++i) {
    source[i] = std::numeric_limits<int16_t>::min()+i;
}

i=0;
for (; i < runs; i += 8) {
    // _mm256_zeroupper();

     dataInt = _mm_loadu_si128((__m128i *) (&source[i]));

      __m256i val_unpacked =_mm256_cvtepi16_epi32(dataInt);
    __m256 converted =  _mm256_cvtepi32_ps(val_unpacked);

    __m256 maxVinFloat = _mm256_set1_ps(max_val);
    converted = _mm256_div_ps(converted, maxVinFloat);

    _mm256_storeu_ps(&target[i], converted);
    _mm256_zeroupper();
}
i = 0;
for (; i < 32; ++i) {
    std::cout << target [ i ] <<"  ";
}}

Однако при компиляции на онлайн-компиляторах вывод будет хорошим даже при использовании оптимизации на уровне 3.Но мой Clion, использующий компилятор, описанный в моем первоначальном посте, выводит несколько бесконечностей, потому что регистр maxVinFloat с максимальными значениями состоит из нулей в одной половине регистра.Таким образом, кажется, что регистр оптимизирован для инициализации только один раз, и другие итерации цикла выводят бесконечности.

EDIT2: Моя ошибка, он выводит бесконечность на онлайн-компиляторы, но я забыл удалить изменяемую часть (это решает проблему) при тестировании просто запустите этот код здесь https://www.tutorialspoint.com/compile_cpp_online.php с оптимизацией -O2

...