Visual Studio C 编译器或 Intel Intrinsics 的 AVX2“_mm256_set_epi64x”函数中的潜在错误

Potential bug in Visual Studio C compiler or in Intel Intrinsics' AVX2 "_mm256_set_epi64x" function

我在 AVX2 函数上遇到了 Intel Intrinsics 的一个非常奇怪的错误,我想在这里分享。要么是我做错了什么(此时我真的看不出是什么),要么是库中的错误。

我的 main.c:

中有这个简单的代码
__int64 test = 0xFFFF'FFFF'FFFF'FFFF;
__m256i ymm = _mm256_set_epi64x(0x0000'0000'0000'0000,
                                0x0000'0000'0000'0000, 
                                0x0000'0000'0000'0000, 
                                test);

分配给变量 ymm 的值出于某些奇怪的原因:

ymm.m256i_i64[0] = 0xffff'ffff'ffff'ffff
ymm.m256i_i64[1] = 0x0000'0000'0000'0000
ymm.m256i_i64[2] = 0x0000'ffff'0000'0000
ymm.m256i_i64[3] = 0x0000'0000'0000'0000

此时我已经调试了几个小时,但不明白为什么 ymm.m256i_i64[2] 会得到这个异常值。请帮忙!

Fun/weird事实: 如果我写这个 C 代码:

__m256i ymm = _mm256_set_epi64x(0x0000'0000'0000'0000,
                                0x0000'0000'0000'0000, 
                                0x0000'0000'0000'0000, 
                                0xFFFF'FFFF'FFFF'FFFF);

然后值正确设置为:

ymm.m256i_i64[0] = 0xffff'ffff'ffff'ffff
ymm.m256i_i64[1] = 0x0000'0000'0000'0000
ymm.m256i_i64[2] = 0x0000'0000'0000'0000
ymm.m256i_i64[3] = 0x0000'0000'0000'0000

注意:我正在使用Visual Studio;他们的编译器和调试工具,如下图所示:

printf下面的代码打印:ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 ff ff ff 00 ff ff 00 00 ff 00 00 00 ff 00 00 00.

似乎结构中其他变量的流氓变化可以改变,因为它们在我添加循环后和以前不一样了......(我不知道循环是否具体进行了更改)。

编辑: 我不是集会的鹰派....一点也不是。我在下图中添加了生成的汇编代码,以防万一它可以帮助任何人帮助我了解发生了什么,如果它不是由我引起的错误:

MSVC until recently did not support any of the epi64x intrinsics in 32-bit mode. In Agner Fog's VCL他写的库

//#if defined (_MSC_VER) && _MSC_VER < 1900 && ! defined (__x86_64__) && ! defined(__INTEL_COMPILER)
// MS compiler cannot use _mm256_set1_epi64x in 32 bit mode, and  
// cannot put 64-bit values into xmm register without using
// mmx registers, and it makes no emms

要在 32 位模式下使用 MSVC 解决此问题,您可以这样做:

union {
    int64_t q[4];
    int32_t r[8];
} u;
u.q[0] = a; u.q[1] = b; u.q[2] = c; u.q[3] = d;
_mm256_setr_epi32(u.r[0], u.r[1], u.r[2], u.r[3], u.r[4], u.r[5], u.r[6], u.r[7]);

或者使用64位模式。