我查看了英特尔的insn reference manual,链接自https://stackoverflow.com/tags/x86/info。
fxam 指令只有一个版本,它在 80 位寄存器上运行。所以是的,那(低效)测试80位临时的正常性。 (更有效的是test $1024, %eax,而不是屏蔽然后cmp。)
According to this、flds 本身会引发非正常异常。我认为这意味着它正在测试实际源,而不是转换为 80 位的结果。该页面说异常异常将设置状态字中的位。
英特尔的参考手册没有说明fld 设置状态字的任何内容,只是关于设置 C1 标志以及未定义 C0、C2 和 C3 的内容。它确实说如果源是非正常的,您可以获得#D FPU 异常,但如果源是 80 位格式,则不会发生这种情况。
如果未启用 FPU 异常,我不知道状态字是否真的会被设置为非规范化。我不是这方面的专家。我对this page(和控制字部分)的解读是,FPU 状态字在大多数指令之后都会更新。如果D 位在控制寄存器 中设置(默认情况下),那么非正规操作数会在状态字 中设置D 位。如果未设置(未屏蔽),则会发生异常。
所以我认为一个测试非正规浮点数的函数看起来像:
isdenormalf:
flds (%rdi) # sets FPU status based on the input to the 32->80bit conversion
fstsw %ax
fstp %st0 # pop
test $2, %al # avoid 16 bit ops (%ax), they're slow on Intel
sete %al # or just branch on flags directly if your compiler's smart
ret
我没有试过这个,所以它可能完全是假的。以一种不加载/弹出我们想要保持加载的数据的内联方式编写它可能并非易事。也许取一个地址 arg,返回一个浮点数(所以它可以在 x87 寄存器中),并有一个带有条件的输出 arg。
我没有看到可以检查 SSE 寄存器中的 float 是否异常的指令。
我认为我有一种(缓慢的)方法可以使用 SSE4.1 或 AVX 的 ROUNDSS 测试非规范化。您需要根据输入的符号使用不同的版本。
对于正值:
- 向
+inf 舍入,非正规数为零
- 向
+inf 舍入,没有非正规数为零。
- 如果两个舍入结果不同,则 denormals-are-zero 会产生影响(意味着输入是 denormal)
负数需要朝-inf 舍入,而不是+inf,否则-0.xx 将始终舍入为零。所以这将有一个分支、两个ROUNDSSes 和一个比较。 IEEE 浮点格式的 Bit-hack 可能会更快。