关注SSE运营商
CMPORDPS - ordered compare packed singles
CMPUNORDPS - unordered compare packed singles
有序和无序是什么意思?我在x86指令集中查找了等效的指令,它似乎只有无序(FUCOM)。
答案 0 :(得分:27)
有序比较检查两个操作数是否均为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
和1.0
的有序比较给出了false
。NaN
和1.0
的无序比较给出了true
。1.0
和1.0
的有序比较给出了true
。1.0
和1.0
的无序比较给出了false
。NaN
和Nan
的有序比较给出了false
。NaN
和NaN
的无序比较给出了true
。答案 1 :(得分:5)
本英特尔指南: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 (有序)vs OR (无序)。
答案 2 :(得分:3)
TL:DR :无序是两个FP值可以具有的关系。 FUCOM
中的“无序”表示当比较结果无序时它不会引发FP异常,而FCOM
则会引发FP异常。这与OQ和OS cmpps
谓词
ORD和UNORD是cmppd
/ cmpps
/ cmpss
/ cmpsd
insn (full tables in the cmppd
entry which is alphabetically first)的两种谓词选择。那个html摘录具有可读的表格格式,但英特尔的官方PDF原始版本要好一些。 (有关链接,请参阅x86标记wiki。)
如果两个浮点操作数都不是NaN ,则它们相互排序。如果是NaN,它们是无序的。即ordered = (x>y) | (x==y) | (x<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指令才会发出无效数字异常的信号。
通常会屏蔽FP异常,因此实际上并不会中断您的程序;它只是设置MXCSR中的位,您可以稍后检查。
这与cmpps
/ vcmpps
的O / UQ与O / US谓词相同。 cmp[ps][sd]
指令的AVX版本具有扩展的谓词选择,因此它们需要一个命名约定来跟踪它们。
O与U告诉您当操作数无序时谓词是否为真。
Q vs. S告诉你,如果任一操作数是一个安静的NaN,是否会引发#I。如果任一操作数是信令NaN,则#I将始终被引发,但这些不是“自然发生的”。您不会将它们作为其他操作的输出,只能通过自己创建位模式(例如,作为函数的错误返回值,以确保以后检测到问题)。
x87等效版使用fcom
或fucom
来设置FPU状态字 - &gt; fstsw ax
- &gt; sahf
,或者最好fucomi
直接设置EFLAGS,如comiss
。
U /非U区别与x87指令相同,与comiss
/ ucomiss
答案 3 :(得分:1)
你可以通过llvm CC的定义理解“有序CC”和“无序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'绝对是'unordered !CC'的反义词。
答案 4 :(得分:-3)
对于Visual C ++内在函数来说,this page可能有帮助吗? :)
r0 := (a0 ord? b0) ? 0xffffffff : 0x0
r1 := (a1 ord? b1) ? 0xffffffff : 0x0
r2 := (a2 ord? b2) ? 0xffffffff : 0x0
r3 := (a3 ord? b3) ? 0xffffffff : 0x0
r0 := (a0 unord? b0) ? 0xffffffff : 0x0
r1 := a1 ; r2 := a2 ; r3 := a3