У меня есть следующий код внутри цикла 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