zeroupper导致错误的结果

时间:2018-11-20 14:39:05

标签: c++ gcc mingw avx avx2

我在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是const变量,等于numeric_limit :: max)。

我在posix线程版本7.2中使用mingw编译器

当我在没有优化的情况下编译程序时,它运行得很好,但是当我打开优化时(我无法控制单个优化,它在我正在研究的项目内部,但是应该使用lvl of优化-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 ] <<"  ";
}}

但是,当使用在线编译器进行编译时,即使使用lvl 3优化,输出也可以。但是我在原始文章中描述的使用编译器的Clion输出了无穷多个,因为具有最大值的寄存器maxVinFloat由寄存器一半的零组成。因此,似乎寄存器已优化为仅初始化一次,并且循环输出无穷大的其他迭代。

EDIT2:我的错误,它确实会在在线编译器上输出无穷大,但是我忘了在测试它时删除易失性部分(解决了问题),只是运行该代码 这里https://www.tutorialspoint.com/compile_cpp_online.php具有-O2优化

0 个答案:

没有答案