为什么 FLD m80fp 不会引发 SNaN 输入异常,而 double 或 float 的 FLD 可以?

Why does FLD m80fp not raise an exception for SNaN inputs while FLD of double or float can?

使用 FLD 时可能出现异常:

  • #IS Stack underflow or overflow occurred.
  • #IA Source operand is an SNaN. Does not occur if the source operand is in double extended-precision floating-point format (FLD m80fp or FLD ST(i)).
  • #D Source operand is a denormal value. Does not occur if the source operand is in double extended-precision floating-point format.

为什么 #IA 例外 "not occur if the source operand is in double extended-precision floating-point format"?

我认为双精度浮点和双扩展精度浮点格式基本相同。两者都能够编码 SNaN。

这种差异是否有任何合乎逻辑的原因,还是就是这样?

fld m64fpm32fp 必须转换为 x87 寄存器中使用的内部 80 位格式。您可以将其视为可以引发#SNaN 异常的转换过程。

fld m80fp 只是纯粹的数据加载,已经是本机内部格式,例如 frstor.

(请注意,AMD64 CPU do 在 SNaN 80 位负载上发出 FP 异常信号;这是 minor differences between AMD and Intel x86-64 的实现)。

从浮点数或双精度数到扩展 80 位的转换必须检查源浮点数的位、扩展尾数并添加显式前导 1 或 0,具体取决于指数字段是否为非零(正常或低于正常水平)。

这种显式与隐式尾数位是 x87 double-extended vs. IEEE binary64 aka double 或 qword 之间的主要区别。两者都可以编码 SNaN,但它们绝对不是 "basically the same" binary32 和 binary64 的方式(只是更宽的字段)。


这 "inconsistency" 大概可以追溯到 8087,当时晶体管预算非常有限;即使不使用通常的转换硬件,fld m80fp 检查 SNaN 也会花费额外的晶体管。

请注意,fld m80fp唯一的 方法,您可以使 x87 FPU 读取 tbyte FP 值(除了 frstor 或更现代的 fxrstorxrstor)。没有 fadd m80fp 或任何东西。因此,任何涉及从内存中读取 m80fp 的操作都不必为 SNaN 引发异常。

大多数 FP 数学指令都有内存源操作数形式,如 fadd st0, m64fp and fadd st0, m32fp,这可能也需要转换为内部格式作为其操作的一部分。因此,您希望检测内存源 SNaN 作为该转换的一部分是有道理的。

因此,如果您正在设计 8087,那么在转换 32 位和 64 位输入时使用处理内存加载检查 SNaN 的逻辑是有意义的,而不是在仅加载 80 位本机格式时。这可能是英特尔最初从中继承该行为的地方,使后来的 CPU 有所不同是没有意义的,因此它们保留了这种行为。

IDK 是否将其视为一个缺点,或者它实际上是否 认为您可以加载 80 位本机 FP 值而不会引发异常。 AMD 显然决定不这样做,并且确实在 SNaN 的 fld m80fp 上发出 FP 异常信号。

或者您可以将其视为一件坏事,即 fld dword / qword 可能会在重新格式化浮点数时引发异常而不会丢失数据,而不进行任何实际计算。


背景:

通常你一开始就不会遇到 SNaN。除以 0 等无效操作的输出是 QNaNs,IIRC。因此,如果您使用整数指令或作为静态常量数据自己创建一个,您只会得到 SNaN。 (我觉得。)

当然,通常您会屏蔽 FP 异常,因此它不会故障,只是在 FP 状态字中设置一个粘滞位。