C++ MSVC&x2B+;2015-SSE编译器错误或程序中的错误/未定义行为?

C++ MSVC&x2B+;2015-SSE编译器错误或程序中的错误/未定义行为?,c++,visual-c++,visual-studio-2015,sse,C++,Visual C++,Visual Studio 2015,Sse,在使用SIMD color lerp函数时,我遇到了一些奇怪的行为,我将其精简为一个最小的程序。本例中的SIMD代码不再执行lerp,而是执行从32位颜色到XMM寄存器的解包,然后再回到32位 在MSVC++2015(更新3)中,在版本x64模式下,以下代码不会产生正确的结果,但在调试x64或版本/调试x86中,它工作正常。这是空的Win32 C++控制台应用程序中的唯一代码: #include <stdint.h> #include <stdio.h> #include

在使用SIMD color lerp函数时,我遇到了一些奇怪的行为,我将其精简为一个最小的程序。本例中的SIMD代码不再执行lerp,而是执行从32位颜色到XMM寄存器的解包,然后再回到32位

在MSVC++2015(更新3)中,在版本x64模式下,以下代码不会产生正确的结果,但在调试x64或版本/调试x86中,它工作正常。这是空的Win32 C++控制台应用程序中的唯一代码:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "emmintrin.h"

struct Color4
{
    uint8_t red;
    uint8_t green;
    uint8_t blue;
    uint8_t alpha;

    Color4(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255)
        : red(red), green(green), blue(blue), alpha(alpha) {}

    explicit Color4(uint32_t rgba)
    {
        red = (uint8_t)(rgba & 0xFF);
        green = (uint8_t)((rgba >> 8)&0xFF);
        blue = (uint8_t)((rgba >> 16) & 0xFF);
        alpha = (uint8_t)((rgba >> 24) & 0xFF);
    }
};

Color4 PackUnpack(Color4 col)
{
    uint32_t tmp;

    memcpy(&tmp, &col, sizeof(tmp));

    __m128 aFloat = _mm_cvtepi32_ps(
        _mm_unpacklo_epi16(
            _mm_unpacklo_epi8(
                _mm_set1_epi32(tmp),
                _mm_setzero_si128()
            ),
            _mm_setzero_si128()
        )
    );

    __m128i ret = _mm_packus_epi16(
        _mm_packs_epi32(
            _mm_cvtps_epi32(aFloat),
            _mm_setzero_si128()
        ),
        _mm_setzero_si128()
    );

    return Color4((uint32_t)_mm_cvtsi128_si32(ret));
}

int main()
{
#ifdef _DEBUG
    printf("DEBUG\n");
#else
    printf("RELEASE\n");
#endif

    Color4 c = PackUnpack(Color4(32, 64, 128, 255));

    // Debug x64 or Debug/Release x86: Prints "32 64 128 255"
    // Release x64: Prints "255 0 0 0"
    printf("%d %d %d %d\n",  c.red, c.green, c.blue, c.alpha);

    return 0;
}
调试x64和所有x86输出为:

RELEASE
255 0 0 0
DEBUG
32 64 128 255
反汇编看起来像是在预先计算一个常量值以加载到XMM寄存器以跳过
\u mm\u set1\u epi32
(请参阅第一条
movdqa
指令)时出错了

我已经在Ubuntu 14.04 x64上的
g++
4.8.4上试过了,它可以在
-O3
打开或关闭的情况下正常工作

所以我的问题是,这是一个编译器错误,是使用未定义/实现定义的行为的结果,还是代码中更普通的错误?


(代码使用通过联合的类型双关来从Color4中获取uint32_t值,我用memcpy替换了它,因为这不是标准的…仍然没有骰子。)

这是由于编译器错误造成的。解决方法是使用

tmp = color.red + 256 * (col.blue + 256 * (col.green + 256 * col.alpha)));

代替了
memcpy
或键入双关语。

实际上不是答案,但是,由于我不喜欢在注释中添加太多文本,这是我可以复制问题的最小代码:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "emmintrin.h"

int main()
{
    uint8_t src[4] = { 32, 64, 128, 255 };

    uint32_t tmp = 0;
    memcpy( &tmp, &src, sizeof( tmp ) );    

    auto a = _mm_set1_epi32( tmp );

    printf( "tmp = 0x%08x\n", tmp );
    printf( "a.m128i_i32[0] = 0x%08x\n", a.m128i_i32[0] );  

    return 0;
}
x64版本的输出:

tmp = 0xff804020
a.m128i_i32[0] = 0x000000ff

这可能会有所帮助:VS 2017中的意外行为是相同的,看起来像是编译器错误。如果使用
tmp=color.red+256*(col.blue+256*(col.green+256*col.alpha)),会发生什么
而不是
memcpy
?@severinpapadeux谢谢你的提示,我下载并安装了这个,但它似乎没有修复它:(@1201programalam,当我用
tmp=col.red+256*(col.blue+256*(col.green+256*col.alpha)]替换该行时;
它工作得很好。感谢您将这一切放在一起。再仔细修改一下,就会发现到达SSE寄存器的值实际上是数组的第4字节。有趣:-)谢谢——我有点震惊,因为我碰到了一个真正的编译器错误,所以我将把这个打开一段时间,以防有人能证明不是这样,但如果他们不能证明,我会将这个标记为已接受!:)(和MS.一起存档)是否已经有一个关于这个的bug存档了,或者这是一个编译器bug只是一个偶然的观察?我不知道它是否存档了,但是生成的错误代码将是一个bug。
tmp = 0xff804020
a.m128i_i32[0] = 0xff804020
tmp = 0xff804020
a.m128i_i32[0] = 0x000000ff