首页 > 解决方案 > 使用 `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 的编译结果的后续问题

标签: cgccx86clangcompiler-optimization

解决方案


优点是编译器自然地发出此代码,无需特殊情况来识别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)


推荐阅读