我试图使用clang和gcc交叉编译一个项目,但在使用\u mm\u max\u ss
时,我发现了一些奇怪的差异,例如。
__m128 a = _mm_set_ss(std::numeric_limits<float>::quiet_NaN());
__m128 b = _mm_set_ss(2.0f);
__m128 c = _mm_max_ss(a,b);
__m128 d = _mm_max_ss(b,a);
现在,当涉及NAN时,我期望std::max
类型行为,但clang和gcc给出不同的结果:
Clang: (what I expected)
c: 2.000000 0.000000 0.000000 0.000000
d: nan 0.000000 0.000000 0.000000
Gcc: (Seems to ignore order)
c: nan 0.000000 0.000000 0.000000
d: nan 0.000000 0.000000 0.000000
当我使用它时,_mm_max_ps做了预期的事情。我尝试过使用-ffast-数学
,-fno-fast-数学
,但似乎没有效果。有什么想法可以让编译器之间的行为相似吗?
这里是锁销连接
我的理解是,IEEE-754要求:(NaN cmp x)
为所有cmp
运算符{==,返回
false
,
那么,问题来了,
_mm_max_ps
是如何实现的?用{
有趣的是,当在链接中禁用优化时,gcc和clang都使用相应的
maxss
指令。两者都产生:
2.000000 0.000000 0.000000 0.000000
nan 0.000000 0.000000 0.000000
这表明,给定:
max(NaN,2.0f)-
(NaN op val)
总是false,返回(val)
,(val op NaN)
总是false,返回(NaN)
启用优化后,编译器可以在编译时自由地预计算
(c)
和(d)
。clang对结果的评估似乎是因为maxss
指令将纠正“仿佛”行为。GCC要么依赖于max()
的另一个实现——它使用GMP和MPFR库进行编译时数字运算——要么就是对\u mm\u max\u ss
语义不太在意。
GCC在godbolt上的10.2和trunk版本中仍然存在错误。所以我想你发现了一只虫子!我还没有回答第二部分,因为我想不出一个通用的黑客可以有效地解决这个问题。
从英特尔的ISA参考:
如果要比较的值均为0.0(任意一个符号),则返回第二个源操作数中的值。如果第二个源操作数中的值是SNaN,则该SNaN将原封不动地返回到目标(即,不返回SNaN的QNaN版本)。
如果此指令只有一个值是NaN(SNaN或QNaN),则第二个源操作数(NaN或有效浮点值)将写入结果。如果不是此行为,而是要求返回来自任一源操作数的NaN,则可以使用一系列指令来模拟MAXSS的操作,例如,比较后跟AND、ANDN和OR。
下面的例子可以解释我的意思: <代码>自动p=标准::使\u共享 变量是默认初始化的(因此具有垃圾值)还是值初始化的(因此具有零值)?我在GCC 5.2和clang 3.6上进行了测试,前者进行值初始化,后者进行默认初始化。我想知道标准对此有什么规定?在我看来,在这种情况下,现代C肯定应该执行值初始化。
根据这篇关于c语言中未定义行为优化的有趣文章,表达式
考虑到这个辅助函数: 它应该将基本类型(和字符串)转换为字符串表达式,当我像这样使用它时,MSVC会出现编译错误: 有了clang,编译起来没有任何问题,但有了MSVC,我明白了: 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 显然,编译器会考虑
GCC接受以下代码: 但是clang拒绝它并带有以下错误: 这似乎表明GCC和clang在重载解析期间执行某些操作的顺序有所不同。GCC似乎在尝试实例化模板候选者的返回类型之前抛弃了模板候选者,因为第二个参数(vs.)中的类型不匹配,而clang似乎反过来做。 谁是对的? 我相信这个问题对模板库的作者有着重要的意义。具体来说,如果clang是正确的,那么模板的作者将不得不做额外的工作,将错误转化为
当一个类具有 constexpr 成员函数并且该成员函数正在 constexpr 上下文中的 l 值对象上求值时,clang 和 gcc 不同意结果是否为 constexpr 值。为什么?是否有既不需要默认可构造性也不需要复制可构造性的解决方法? 当对象按值传递时,两个编译器都会成功编译。 Clang版本trunk,8,7: 和 gcc 版本主干,8.1、7.4:编译没有错误 https://go
我知道movzx可以用于打破依赖关系,但我偶然发现Clang和GCC都使用了movzx,我真的看不出它们有什么好处。下面是我在godbolt上尝试的一个简单示例: 对于gcc12-O3: 如果我理解正确,这里的第一个movzx打破了对前一个eax值的依赖,但是第二个movzx在做什么?我不认为它可以打破任何依赖,也不应该影响结果。 有了clang14-O3,就更奇怪了: 它在movzx似乎更合理的