c - 使用 `setp` 代替 `setb` 有什么好处吗?
问题描述
编译时
double isnan(double x){
return x!=x
}
clang 和 gcc都使用parity-flag PF
:
_Z6is_nand: # @_Z6is_nand
ucomisd %xmm0, %xmm0
setp %al
retq
但是,比较的两种可能结果是:
NaN Not-Nan
ZF 1 1
PF 1 0
CF 1 0
这意味着也可以使用CF
- 标志作为替代,即setb
代替setp
.
setp
使用over有什么好处setb
,还是巧合,两个编译器都使用奇偶校验标志?
PS:这个问题是了解 std::isnan 的编译结果的后续问题
解决方案
优点是编译器自然地发出此代码,无需特殊情况来识别x!=x
并将其转换为!(x >= x)
.
如果没有 -ffast-math,x != y
则必须检查 PF 以查看比较是否有序,然后检查 ZF 是否相等。在两个输入相同的特殊情况下,可能像 CSE 这样的正常优化机制可以摆脱 ZF 检查,只留下 PF。
在这种情况下,setb
不会更糟,但它绝对没有优势,而且对人类来说更令人困惑,它可能需要更多的特殊情况代码让编译器发出它。
您建议的转换仅在使用带有使用 CF 的特殊指令的结果时才有用,例如adc
. 例如,nan_counter += arr[i] != arr[i]
。自动矢量化很简单(cmp_unord_ps
/ psubd
),但标量清理(或非数组输入的标量用例)可以使用ucomiss
/adc $0, %eax
而不是ucomiss
/ setp
/ add
。
这样可以节省一条指令,以及 Broadwell 及更高版本以及 AMD 上的 uop。(早期的 Intel CPU 有 2 uop adc,除非它们是特殊情况$0
,因为它们不支持 3 输入 uop)