short version: Unordered is a relation two FP values can have. Scalar compares set FLAGS so you can check any condition you want (e.g. ucomisd xmm0, xmm1
/ jp unordered
), but SIMD compares need to encode the condition (predicate) into the instruction to be checked in parallel to produce a vector with element values of 0 / 0xFF.... Nowhere to put a separate FLAGS result for each element.
The "Unordered" in FUCOM
means it doesn't raise an FP "invalid" exception when the comparison result is unordered, while FCOM
does. This is the same as the distinction between OQ and OS cmpps
predicates, not the "unordered" predicate. (See the "Signals
#IA on
QNAN" column in the cmppd
docs in Intel's asm manuals. (cmppd
is alphabetically first and has the more complete docs, vs. cmpps / cmpss/sd))
(FP exceptions are masked by default so they don't cause the CPU to trap to a hardware exception handler, just set sticky flags in MXCSR, or the legacy x87 status word for x87 instructions.)
ORD and UNORD are two choices of predicate for the cmppd
/ cmpps
/ cmpss
/ cmpsd
insns (full tables in the cmppd
entry which is alphabetically first). That html extract has readable table formatting, but Intel's official PDF original is somewhat better. (See the x86 tag wiki for links).
Two floating point operands are ordered with respect to each other if neither is NaN. They're unordered if either is NaN. i.e. ordered = (x>y) | (x==y) | (x<y);
. That's right, with floating point it's possible for none of those things to be true. For more Floating Point madness, see Bruce Dawson's excellent series of articles.
cmpps
takes a predicate and produces a vector of results, instead of doing a comparison between two scalars and setting flags so you can check any predicate you want after the fact. So it needs specific predicates for everything you can check.
The scalar equivalent is comiss
/ ucomiss
to set ZF/PF/CF from the FP comparison result (which works like the x87 compare instructions (see the last section of this answer), but on the low element of XMM regs).
To check for unordered, look at PF
. If the comparison is ordered, you can look at the other flags to see whether the operands were greater, equal, or less (using the same conditions as for unsigned integers, like jae
for Above or Equal).
The COMISS instruction differs from the UCOMISS instruction in that it signals a SIMD floating-point invalid operation exception (#I) when a source operand is either a QNaN or SNaN. The UCOMISS instruction signals an invalid numeric exception only if a source operand is an SNaN.
(SNaN is not naturally occurring; operations like sqrt(-1)
or inf - inf
will produce QNaN if exceptions are masked, else trap and not produce a result.)
Normally FP exceptions are masked, so this doesn't actually interrupt your program; it just sets the bit in the MXCSR which you can check later.
This is the same as O/UQ vs. O/US flavours of predicate for cmpps
/ vcmpps
. The AVX version of the cmp[ps][sd]
instructions have an expanded choice of predicate, so they needed a naming convention to keep track of them.
The O vs. U tells you whether the predicate is true when the operands are unordered.
The Q vs. S tells you whether #I will be raised if either operand is a Quiet NaN. #I will always be raised if either operand is a Signalling NaN, but those are not "naturally occurring". You don't get them as outputs from other operations, only by creating the bit pattern yourself (e.g. as an error-return value from a function, to ensure detection of problems later).
The x87 equivalent is using fcom
or fucom
to set the FPU status word -> fstsw ax
-> sahf
, or preferably fucomi
to set EFLAGS directly like ucomiss
.
The U / non-U distinction is the same with x87 instructions as for comiss
/ ucomiss