有关 x87 状态字的信息,请参阅 this page。
请注意,16 位状态字存储到ax,但test 指令只查看高 8 位(ah)。所以41h 匹配状态字的C0 和C3 位。在 ah 上使用 8 位测试可避免英特尔 CPU 因使用 16 位 test 和 imm16 而导致减速。 (操作数大小前缀改变指令其余部分的长度,即所谓的长度改变前缀解码器停顿)。
fld / fcomp / fld / fnstsw:这对我来说也很奇怪。我想知道目标是否是基于内存位置设置状态字中的非规范位,但基于fcomp 设置C0 等等。 (这不是你得到的,因为fld 使C0-3 未定义或设置。)
英特尔的 insn 参考手册说 fld 未定义 C0 和 C3,因此生成此代码的编译器取决于某些特定行为。也许没有fwait,状态字不会从fcomp 更新?我还没有理解整个fwait 的事情。我还没有找到(或努力寻找)关于在旧 CPU 上何时需要 fwait 以及何时不需要的解释。据我了解,您永远不会在 P5 或更高版本上这样做。
无论如何,我认为这段代码的作用是:
if (! ([L1000F168] > [L1000A2F0]))
goto L100012F0;
测试 not-greater 与测试 <= 或无序相同。这假定fld 实际上并未修改C0 和C3。也许手册只说它没有定义它们,因为它可以在加载非正规或其他条件时设置它们?或者也许它在当前的硅中根本没有。或者也许这是英特尔手册中的另一个错误,这实际上是众所周知的。或者也许这段代码不再起作用了!最好使用调试器对其进行测试。
我认为获得程序员可能希望的结果的更明智的方法是
fld qword ptr [L1000F168]
fcom qword ptr [L1000A2F0]
fnstsw ax
test ah,41h ; C0|C3: both zero iff st(0) > [L1000A2F0]
jnz L100012F0
由于 OP 说代码是编译器输出,我猜这意味着它没有很好的 x87 优化来避免弹出/重新加载相同的值。
For P6 and later CPUs:
fld qword ptr [L1000F168]
fcomi qword ptr [L1000A2F0]
jna L100012F0 ; jump unless st(0) > [L1000A2F0]
我可能对其中一个比较有倒退的感觉,所以如果有什么不合理的地方,请仔细检查。
这段代码来自哪里?是编译器输出吗?或者可能是手写的 asm?