英语不是我的母语,请原谅我的语法错误
我的机器环境是
AMD 5900x, win10 latest, VS2022 MSVC lateset
字符串
下面的代码已经在我的机器和我同事的机器(与我的机器非常相似)上通过了编译(debug-X86,release-x86 MSVC),但是输出不是预期的
#include <intrin.h>
#include <iostream>
#include <xmmintrin.h>
int main(int argc, char* argv[])
{
union
{
float f[2];
__m64 m;
} a = {{10.f, 200.f}};
a.m = _mm_shuffle_pi16(a.m, _MM_SHUFFLE(1, 0, 3, 2));
std::cout << a.f[0] << " " << a.f[1] << std::endl;
std::cout << a.f[0] << " " << a.f[1] << std::endl;
return 0;
}
expected output:
200 10
200 10
ACTUAL output:
-nan(ind) 10
200 10
// note: no math operation undertake between two std::cout
的数据
我已经检查了二进制数据,它们在IEEE 754标准中都是法律的:
x1c 0d1x的数据
的
拆卸是很正常的:
的
这真的让我觉得有任何上游BUG?或任何编译环境问题?任何类似的情况,你遇到过?任何建议或进一步的信息需要?提前感谢。
样本1:相同代码
Linux kali 6.3.0-kali1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.3.7-1kali1 (2023-06-29) x86_64 GNU/Linux
gcc (Debian 13.1.0-6) 13.1.0
g++ (Debian 13.1.0-6) 13.1.0
Debian clang version 14.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
compile command:
g++ a.cpp
clang++ -o aaa a.cpp
的字符串
输出(对于两种编译方法):
200 10
200 10
型
的
1条答案
按热度按时间balp4ylt1#
虽然我不知道在赋值给
a.m
和打印内容之间到底发生了什么,但代码本身存在一个bug:_mm_shuffle_pi16
是MMX内在的,您没有调用_mm_empty
(或_m_empty
),因此FPU状态仍处于MMX模式。这将在以后中断x87风格的FPU指令。(所以是32位),所以很可能在某个时候使用了x87指令。64位代码大多不使用x87指令,在这种情况下,它可能看起来没有什么不好的事情发生,这可以解释为什么代码似乎在64位kali Linux上工作。MMX在这一点上是retrocomputing。你可以添加
_mm_empty
来修复这段代码,但你也可以使用SSE。放弃union(如果需要的话,你可以使用“cast”intrinsic家族来进行安全的重新解释,但你不需要它,因为SSE有一个浮点 Shuffle ),并做一些类似的事情:字符串
历史上有some compiler bugs with
_mm_empty
,但这不是你在程序中看到的,它开始就没有_mm_empty
。