使用FLD时可能出现以下异常:
#IS
发生堆栈下溢或溢出。
#IA
源操作数是SNaN。如果源操作数为双精度扩展浮点格式(FLD m80fp或FLD ST(i)),则不会发生。
#D
源操作数是非正规值。如果源操作数为双精度扩展浮点格式,则不会发生。
为什么#IA异常“如果源操作数为双精度扩展浮点格式则不会发生”?
我认为双精度浮点数和双扩展精度浮点数格式基本相同。两者都能够编码SNaN。
有什么逻辑上的原因导致这种差异,或者仅仅是它的现状?
最佳答案
fld m64fp
和m32fp
必须转换为x87寄存器中使用的内部80位格式。您可以将其视为可能引发#SNaN异常的转换过程。fld m80fp
只是纯数据加载,已经采用本机内部格式,例如frstor
。
(请注意,AMD64 CPU确实在SNaN 80位负载上发出FP异常信号;这是x86-64的minor differences between AMD and Intel实现之一)。
从float或double到扩展的80位的转换必须检查源float的位,扩展尾数并根据指数字段为非零(正常或次正规)添加显式前导1或0。
此显式尾数与隐式尾数位是x87 double-extended与IEEE binary64 aka double或qword之间的主要区别。两者都可以对SNaN进行编码,但是它们绝对与binary32和binary64的方式“基本相同”(只是更宽的字段)。
这种“不一致”大概可以追溯到8087年,当时晶体管预算非常有限。即使不使用常规的转换硬件,也要进行fld m80fp
检查SNaN会花费额外的晶体管。
请注意,fld m80fp
是使x87 FPU读取tbyte
FP值(frstor
或更现代的fxrstor
或xrstor
除外)的唯一方法。没有fadd m80fp
或任何东西。因此,任何涉及从内存中读取m80fp的操作都不必为SNaN引发异常。
大多数FP数学指令都有内存源操作数形式,例如fadd st0, m64fp
and fadd st0, m32fp
,可能还需要将其转换为内部格式作为其操作的一部分。因此,在此转换过程中,您需要检测一个内存源SNaN才有意义。
因此,如果您正在设计8087,那么在转换32位和64位输入时(而不是仅在加载80位本机格式时)具有处理SNaN的内存检查逻辑的逻辑将很有意义。这可能是Intel最初从中继承该行为的地方,并且使以后的CPU有所不同,因此保留了这种行为是没有意义的。
IDK是将其视为缺点,还是实际上可以很好地认为您可以加载80位本机FP值而不会引发异常。 AMD显然决定不这样做,并且确实在SNaN的fld m80fp
上发出FP异常信号。
或者,您可以将其视为不好的事情,即fld dword / qword
仅在重新格式化浮点数时就可能引发异常,而不会丢失数据,并且不进行任何实际计算。
背景:
通常,您一开始就不会遇到SNaN。无效运算(例如被0除)的输出是QNaN,IIRC。因此,仅当您使用整数指令或作为静态常量数据创建自己时,才获得SNaN。 (我认为。)
当然,通常您会屏蔽FP异常,这样就不会出错,只需在FP状态字中设置一个粘性位即可。
关于assembly - 为什么FLD m80fp不会在SNaN输入上引发异常,而double或float的FLD可以呢?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61024467/