在高级向量扩展(AVX)中,比较指令如_m256_cmp_ps,最后一个参数是比较谓词.谓词的选择压倒了我.它们似乎是类型,排序,信号的三重奏.例如_CMP_LE_OS是'小于或等于,有序,信令.
对于初学者来说,是否存在选择信令或非信令的性能原因,同样,有序或无序的速度比另一个更快?
什么'非信令'甚至意味着什么?我根本无法在文档中找到这个.任何关于何时选择什么的经验法则?
以下是avxintrin.h的谓词选择:
/* Compare */
#define _CMP_EQ_OQ 0x00 /* Equal (ordered, non-signaling) */
#define _CMP_LT_OS 0x01 /* Less-than (ordered, signaling) */
#define _CMP_LE_OS 0x02 /* Less-than-or-equal (ordered, signaling) */
#define _CMP_UNORD_Q 0x03 /* Unordered (non-signaling) */
#define _CMP_NEQ_UQ 0x04 /* Not-equal (unordered, non-signaling) */
#define _CMP_NLT_US 0x05 /* Not-less-than (unordered, signaling) */
#define _CMP_NLE_US 0x06 /* Not-less-than-or-equal (unordered, signaling) */
#define _CMP_ORD_Q 0x07 /* Ordered (nonsignaling) */
#define _CMP_EQ_UQ 0x08 /* Equal (unordered, non-signaling) */
#define _CMP_NGE_US 0x09 /* Not-greater-than-or-equal (unord, signaling) */
#define _CMP_NGT_US 0x0a /* Not-greater-than (unordered, signaling) */
#define _CMP_FALSE_OQ 0x0b /* False (ordered, non-signaling) */
#define _CMP_NEQ_OQ 0x0c /* Not-equal (ordered, non-signaling) */
#define _CMP_GE_OS 0x0d /* Greater-than-or-equal (ordered, signaling) */
#define _CMP_GT_OS 0x0e /* Greater-than (ordered, signaling) */
#define _CMP_TRUE_UQ 0x0f /* True (unordered, non-signaling) */
#define _CMP_EQ_OS 0x10 /* Equal (ordered, signaling) */
#define _CMP_LT_OQ 0x11 /* Less-than (ordered, non-signaling) */
#define _CMP_LE_OQ 0x12 /* Less-than-or-equal (ordered, non-signaling) */
#define _CMP_UNORD_S 0x13 /* Unordered (signaling) */
#define _CMP_NEQ_US 0x14 /* Not-equal (unordered, signaling) */
#define _CMP_NLT_UQ 0x15 /* Not-less-than (unordered, non-signaling) */
#define _CMP_NLE_UQ 0x16 /* Not-less-than-or-equal (unord, non-signaling) */
#define _CMP_ORD_S 0x17 /* Ordered (signaling) */
#define _CMP_EQ_US 0x18 /* Equal (unordered, signaling) */
#define _CMP_NGE_UQ 0x19 /* Not-greater-than-or-equal (unord, non-sign) */
#define _CMP_NGT_UQ 0x1a /* Not-greater-than (unordered, non-signaling) */
#define _CMP_FALSE_OS 0x1b /* False (ordered, signaling) */
#define _CMP_NEQ_OS 0x1c /* Not-equal (ordered, signaling) */
#define _CMP_GE_OQ 0x1d /* Greater-than-or-equal (ordered, non-signaling) */
#define _CMP_GT_OQ 0x1e /* Greater-than (ordered, non-signaling) */
#define _CMP_TRUE_US 0x1f /* True (unordered, signaling) */
Run Code Online (Sandbox Code Playgroud)
小智 30
Ordered与Unordered有关,如果其中一个操作数包含NaN,则比较是否为真(请参阅有序/无序比较是什么意思?).信令(S)与非信令(Q表示安静?)将确定如果操作数包含NaN则是否引发异常.
从性能的角度来看,这些都应该是相同的(假设当然没有例外).如果你想在有NaN时收到警报,那么你需要信号.对于有序与无序,这一切都取决于你想如何处理NaNs.
Dav*_*son 14
当任一操作数为 NaN 时,有序与无序决定结果值。
falseNaN 操作数的有序比较返回。
1.0和1.0给出true (香草平等)。NaN和1.0给出false.1.0和NaN给出false.NaN和NaN给出false.trueNaN 操作数的无序比较返回。
1.0和1.0给出true(香草平等)。NaN和1.0给出true.1.0和NaN给出true.NaN和NaN给出true.信令与非信令之间的差异仅影响 MXCSR 的值。要观察效果,您需要清除 MXCSR,执行一个或多个比较,然后读取 MXCSR(感谢 Peter Cordes 澄清这一点!)。
枚举值的顺序非常混乱。它有助于将它们放在桌子上......
| 比较 | 有序(非信令) | 无序(非信令) |
|---|---|---|
| a < b | _CMP_LT_OQ | _CMP_NGE_UQ |
| a <= b | _CMP_LE_OQ | _CMP_NGT_UQ |
| a == b | _CMP_EQ_OQ | _CMP_EQ_UQ |
| 一个!= b | _CMP_NEQ_OQ | _CMP_NEQ_UQ |
| a >= b | _CMP_GE_OQ | _CMP_NLT_UQ |
| a > b | _CMP_GT_OQ | _CMP_NLE_UQ |
| 真的 | _CMP_ORD_Q | _CMP_TRUE_UQ(无用) |
| 错误的 | _CMP_FALSE_OQ(无用) | _CMP_UNORD_Q |
使用 MXCSR“信令”:
| 比较 | 有序(信令) | 无序(信令) |
|---|---|---|
| a < b | _CMP_LT_OS | _CMP_NGE_US |
| a <= b | _CMP_LE_OS | _CMP_NGT_US |
| a == b | _CMP_EQ_OS | _CMP_EQ_US |
| 一个!= b | _CMP_NEQ_OS | _CMP_NEQ_美国 |
| a >= b | _CMP_GE_OS | _CMP_NLT_US |
| a > b | _CMP_GT_OS | _CMP_NLE_US |
| 真的 | _CMP_ORD_S | _CMP_TRUE_US(无用) |
| 错误的 | _CMP_FALSE_OS(无用) | _CMP_UNORD_S |
枚举值的顺序可以解释为:
前四个操作是规范的 ( EQ, LT, LE, UNORD)。请注意,如果0x00和0x03值为LE/UNORD或UNORD/ LE,则可以将四个规范操作视为两个单独位的组合,但这对于它们的实际顺序是不可能的。
其余的操作是前四个操作的转换。
该0x04位精确地反转结果值,这也有效地切换了有序与无序。例如,LT_O变成NLT_U,它类似于GE,但请参阅无序命名规则。
该0x08位切换有序与无序(不更改任何其他内容)。
设置0x04和0x08位会否定数值操作数的结果,同时保留 NaN 操作数的相同排序行为。例如,LT_O变成GE_O。
请注意,当比较是无序的(即设置了0x04or之一0x08)时,将使用否定名称:NGE代替LT、NGT代替LE、NLT代替GE和NLE代替GT; 然而,这两个EQ并NEQ需要同时定义有序和无序的变体,所以这些名字只有在改变0x04否定转型,而不是0x08orderedness-切换转变。
FALSE/TRUE都大多无用0x08的变换UNORD/ ORD,总是返回相同的值。例如,UNORD( 0x03)false如果两个操作数都是数字,或者true其中一个是NaN; 添加0x08,我们得到FALSE( 0x0b),它切换了NaN操作数的行为,导致它在false两种情况下都返回。
有趣的事实:TRUE操作并不总是完全没用。在 AVX2 之前,它是将 YMM 寄存器设置为全 1 的最紧凑的机制。有关详细信息,请参阅https://godbolt.org/z/Yb5TjP(感谢 Peter Cordes)。
该0x10位切换信号与否。请注意,规范操作LE和LT正在发信号,而EQ和UNORD不是,因此设置该0x10位会从LE/LTops 中删除信号并将其添加到EQ/UNORDops。因为这显然是明智的,而且一点也不令人困惑。