【问题标题】:What does ordered / unordered comparison mean?有序/无序比较是什么意思?
【发布时间】:2012-01-27 11:29:56
【问题描述】:

看 SSE 运营商

CMPORDPS - ordered compare packed singles
CMPUNORDPS - unordered compare packed singles

有序和无序是什么意思?我在 x86 指令集中寻找等效指令,它似乎只有无序(FUCOM)。

【问题讨论】:

标签: assembly x86 floating-point sse


【解决方案1】:

有序比较检查两个操作数是否都不是NaN。相反,无序比较检查任一操作数是否为NaN

此页面提供了更多相关信息:

这里的想法是与NaN 的比较是不确定的。 (无法决定结果)因此,有序/无序比较检查是否是(或不是)这种情况。

double a = 0.;
double b = 0.;

__m128d x = _mm_set1_pd(a / b);     //  NaN
__m128d y = _mm_set1_pd(1.0);       //  1.0
__m128d z = _mm_set1_pd(1.0);       //  1.0

__m128d c0 = _mm_cmpord_pd(x,y);    //  NaN vs. 1.0
__m128d c1 = _mm_cmpunord_pd(x,y);  //  NaN vs. 1.0
__m128d c2 = _mm_cmpord_pd(y,z);    //  1.0 vs. 1.0
__m128d c3 = _mm_cmpunord_pd(y,z);  //  1.0 vs. 1.0
__m128d c4 = _mm_cmpord_pd(x,x);    //  NaN vs. NaN
__m128d c5 = _mm_cmpunord_pd(x,x);  //  NaN vs. NaN

cout << _mm_castpd_si128(c0).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c1).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c2).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c3).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c4).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c5).m128i_i64[0] << endl;

结果:

0
-1
-1
0
0
-1

如果操作数是可比较的(两个数字都不是 NaN),则有序返回 true:

  • 有序比较 1.01.0 得到 true
  • 有序比较 NaN1.0 得到 false
  • 有序比较 NaNNaN 得到 false

无序比较正好相反:

  • 无序比较 1.01.0 得到 false
  • 无序比较 NaN1.0 得到 true
  • 无序比较 NaNNaN 得到 true

【讨论】:

  • 谢谢。信令与非信令比较呢?例如_CMP_LE_OS 与 avxintrin.h 中的 _CMP_LE_OQ
  • @Bram Bleh... 老实说,我什至从未听说过这些。所以我不会知道。最好将其作为一个单独的问题提出,以便其他人回答。
  • 我在您的答案中添加了 NaN vs NaN 以使其完整。
  • @MarkLakata 谢谢!
  • @Mysticial:OQ 与 OS 控制是否会在存在 QNaN 时引发 #I(FP 无效),或者仅在存在 SNaN 时(AFAIK 不是自然发生的;你不会从任何类型的除以零或 inf-inf 或任何东西中获取 SNaN。)
【解决方案2】:

也许this page 对 Visual C++ 内在函数有帮助? :)

CMPORDPS

r0 := (a0 ord? b0) ? 0xffffffff : 0x0
r1 := (a1 ord? b1) ? 0xffffffff : 0x0
r2 := (a2 ord? b2) ? 0xffffffff : 0x0
r3 := (a3 ord? b3) ? 0xffffffff : 0x0

CMPUNORDPS

r0 := (a0 unord? b0) ? 0xffffffff : 0x0
r1 := a1 ; r2 := a2 ; r3 := a3

【讨论】:

  • 这只是显示了谓词如何应用于向量操作数的每个元素。它没有说明谓词条件是什么。
【解决方案3】:

本英特尔指南:http://intel80386.com/simd/mmx2-doc.html 包含两个相当简单明了的示例:

CMPORDPS 比较有序并行标量

操作码周期指令 0F C2 .. 07 2 (3) CMPORDPS xmm reg,xmm reg/mem128

CMPORDPS op1, op2

op1 包含 4 个单精度 32 位浮点值 op2 包含 4 个单精度 32 位浮点值

op1[0] = (op1[0] != NaN) && (op2[0] != NaN)
op1[1] = (op1[1] != NaN) && (op2[1] != NaN)
op1[2] = (op1[2] != NaN) && (op2[2] != NaN)
op1[3] = (op1[3] != NaN) && (op2[3] != NaN)

TRUE  = 0xFFFFFFFF
FALSE = 0x00000000

CMPUNORDPS 比较无序并行标量

操作码周期指令 0F C2 .. 03 2 (3) CMPUNORDPS xmm reg,xmm reg/mem128

CMPUNORDPS op1, op2

op1 包含 4 个单精度 32 位浮点值 op2 包含 4 个单精度 32 位浮点值

op1[0] = (op1[0] == NaN) || (op2[0] == NaN)
op1[1] = (op1[1] == NaN) || (op2[1] == NaN)
op1[2] = (op1[2] == NaN) || (op2[2] == NaN)
op1[3] = (op1[3] == NaN) || (op2[3] == NaN)

TRUE  = 0xFFFFFFFF
FALSE = 0x00000000

区别在于 AND(有序)与 OR(无序)。

【讨论】:

    【解决方案4】:

    短版:无序是两个 FP 值可以具有的关系。标量比较设置的 FLAGS,因此您可以检查您想要的任何条件(例如 ucomisd xmm0, xmm1 / jp unordered),但 SIMD 比较需要将条件(谓词)编码到要并行检查的指令中,以生成元素值为0 / 0xFF.... 无处为每个元素放置单独的 FLAGS 结果。

    FUCOM 中的“无序”表示当比较结果无序时它不会引发 FP“无效”异常,而 FCOM 会。这与 OQ 和 OS cmpps 谓词之间的区别相同,而不是“无序”谓词。 (见“信号 #IA 开启 英特尔 asm 手册中cmppd 文档中的“QNAN”列。(cmppd 按字母顺序排列,文档更完整,与 cmpps / cmpss/sd 相比))

    FP exceptions 默认情况下被屏蔽,因此它们不会导致 CPU 陷入硬件异常处理程序,只需在 MXCSR 中设置粘性标志,或为 x87 指令设置传统 x87 状态字。)


    ORD 和 UNORD 是 cmppd / cmpps / cmpss / cmpsd insns (full tables in the cmppd entry which is alphabetically first) 的两个谓词选择。该 html 提取具有可读的表格格式,但英特尔的官方 PDF 原件要好一些。 (有关链接,请参阅 标签 wiki)。

    两个浮点如果都不是NaN,则操作数相互排序。如果其中一个是 NaN,则它们是无序的。即ordered = (x&gt;y) | (x==y) | (x&lt;y);。没错,使用浮点数,这些事情都不可能是真的。更多浮点疯狂,见Bruce Dawson's excellent series of articles.

    cmpps 接受一个谓词并产生一个结果向量,而不是在两个标量之间进行比较并设置标志,这样您就可以在事后检查您想要的任何谓词。因此,它需要特定的谓词来检查您可以检查的所有内容。


    标量等效项是 comiss / ucomiss 从 FP 比较结果中设置 ZF/PF/CF(其工作方式类似于 x87 比较指令(请参阅此答案的最后一部分),但在低元素XMM 规则)。

    要检查无序,请查看PF。如果比较是有序的,您可以查看其他标志以查看操作数是更大、等于还是小于 (using the same conditions as for unsigned integers, like jae for Above or Equal)。


    The COMISS instruction 与 UCOMISS 指令的不同之处在于,当源操作数是 QNaN 或 SNaN 时,它会发出 SIMD 浮点无效操作异常 (#I) 信号。仅当源操作数是 SNaN 时,UCOMISS 指令才会发出无效数值异常。

    (SNaN 不是自然发生的;sqrt(-1)inf - inf 之类的操作会在屏蔽异常时产生 QNaN,否则会陷入陷阱并且不会产生结果。)

    通常 FP 异常会被屏蔽,因此这实际上不会中断您的程序;它只是在 MXCSR 中设置位,您可以稍后检查。

    这与 cmpps / vcmpps 的 O/UQ 与 O/US 风格的谓词相同cmp[ps][sd] 指令的 AVX 版本有一个扩展的谓词选择,因此他们需要一个命名约定来跟踪它们。

    当操作数无序时,O vs. U 告诉您谓词是否为真。

    Q 与 S 告诉您如果任一操作数是 Quiet NaN,是否会引发 #I。 #I 如果任一操作数是 Signaling NaN,将始终被引发,但这些都不是“自然发生的”。您不能将它们作为其他操作的输出,只能通过自己创建位模式(例如,作为函数的错误返回值,以确保以后检测到问题)。


    x87 等效项是使用fcomfucom 设置FPU 状态字-> fstsw ax -> sahf,或者最好使用fucomi 直接设置EFLAGS,如ucomiss

    x87 指令的 U / 非 U 区别与 comiss / ucomiss 相同

    【讨论】:

      【解决方案5】:

      你可以通过llvm CC的定义来理解'ordered CC'和'unordered CC'的含义,其中'CC'表示CondCode。 在'llvm/include/llvm/CodeGen/ISDOpcodes.h'(我的源代码版本是llvm-10.0.1)中,你可以看到CondCode的枚举如下:

      enum CondCode {
      // Opcode          N U L G E       Intuitive operation
      SETFALSE,      //    0 0 0 0       Always false (always folded)
      SETOEQ,        //    0 0 0 1       True if ordered and equal
      SETOGT,        //    0 0 1 0       True if ordered and greater than
      SETOGE,        //    0 0 1 1       True if ordered and greater than or equal
      SETOLT,        //    0 1 0 0       True if ordered and less than
      SETOLE,        //    0 1 0 1       True if ordered and less than or equal
      SETONE,        //    0 1 1 0       True if ordered and operands are unequal
      SETO,          //    0 1 1 1       True if ordered (no nans)
      SETUO,         //    1 0 0 0       True if unordered: isnan(X) | isnan(Y)
      SETUEQ,        //    1 0 0 1       True if unordered or equal
      SETUGT,        //    1 0 1 0       True if unordered or greater than
      SETUGE,        //    1 0 1 1       True if unordered, greater than, or equal
      SETULT,        //    1 1 0 0       True if unordered or less than
      SETULE,        //    1 1 0 1       True if unordered, less than, or equal
      SETUNE,        //    1 1 1 0       True if unordered or not equal
      SETTRUE,       //    1 1 1 1       Always true (always folded)
      // Don't care operations: undefined if the input is a nan.
      SETFALSE2,     //  1 X 0 0 0       Always false (always folded)
      SETEQ,         //  1 X 0 0 1       True if equal
      SETGT,         //  1 X 0 1 0       True if greater than
      SETGE,         //  1 X 0 1 1       True if greater than or equal
      SETLT,         //  1 X 1 0 0       True if less than
      SETLE,         //  1 X 1 0 1       True if less than or equal
      SETNE,         //  1 X 1 1 0       True if not equal
      SETTRUE2,      //  1 X 1 1 1       Always true (always folded)
      SETCC_INVALID       // Marker value.
      };
      

      这意味着:对于浮点条件比较,'ordered CC'表示'ordered & CC',而'unordered CC'表示'unordered |抄送'。

      换句话说,在浮点比较中,NaN 是“非数字”,

      • 'ordered CC' 在以下情况下返回 true:'两个操作数都不是 NaN'并且'CC 为 true'
      • “无序 CC”在以下情况下返回 true:“一个或多个操作数为 NaN”或“CC 为 true”

      你也可以看到,'ordered CC' 绝对是 'unordered !CC' 的反义词。

      【讨论】:

      • 请注意,这些标志位列确实反映您可以在 asm / 机器代码中用作立即数的位模式。 (或者像 _CMP_EQ_UQ 这样的常量的 immintrin.h 值,即 0)。但是,是的,有用的表格,虽然我认为英特尔的 asm 手册中的表格已经涵盖了每个谓词的 4 种可能关系:felixcloutier.com/x86/cmppd
      • 感谢您的意见。事实上,LLVM CondCode 枚举在 asm 程序中不是实际编码或直接编码。它只是用于指令选择和降低的llvm SelectionDAG的条件代码的表示。 Intel 的 asm 手册列出了比较谓词操作数的编码及其对应的比较结果。它也是理解有序/无序比较的好来源。
      猜你喜欢
      • 1970-01-01
      • 2018-05-09
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 2010-11-20
      • 2015-08-16
      • 2011-03-26
      • 2016-11-28
      相关资源
      最近更新 更多