我检查了英特尔的insn 参考手册,链接自https://stackoverflow.com/tags/x86/info。
该指令只有一个版本fxam
,它在 80 位寄存器上运行。所以是的,那(低效)测试80位临时的正常性。(更有效的是test $1024, %eax
,而不是屏蔽然后cmp
。)
据此,flds
它本身会引发一个 Denormal 异常。我认为这意味着它正在测试实际源,而不是转换为 80 位的结果。该页面说异常异常将设置状态字中的位。
英特尔的参考手册没有说明fld
设置状态字的任何内容,只是关于设置 C1 标志以及未定义 C0、C2 和 C3 的内容。它确实说如果源是非正常的,您可以获得#D FPU 异常,但如果源是 80 位格式,则不会发生这种情况。
如果未启用 FPU 异常,我不知道状态字是否真的会被设置为非规范化。我不是这方面的专家。我对本页(和控制字部分)的阅读是 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。
我没有看到可以检查float
SSE 寄存器中的 a 是否异常的指令。
我想我有一种(缓慢的)方法来测试 SSE4.1 或 AVX 的非规范化ROUNDSS
。您需要根据输入的符号使用不同的版本。
对于正值:
- 用非正规数朝四舍五入
+inf
- 为零
- 朝
+inf
没有非正规数的方向舍入为零。
- 如果两个舍入结果不同,则 denormals-are-zero 会产生影响(意味着输入是 denormal)
负数需要向-inf
, not进行四舍五入+inf
,否则-0.xx
将始终四舍五入为零。所以这会有一个分支、两个ROUNDSS
es 和一个比较。IEEE 浮点格式的 Bit-hacks 可能会更快。