如果我在rax
中有某个值(位模式,假设全为零),我可以将其存储在st0
中而无需存储和从内存中加载吗?
您可以使用许多指令将常量加载到FPU寄存器堆栈。我认为这里最有用的是FLD1
和FLDZ
,它们分别将+1.0和+0.0加载到堆栈上。如果RAX
可能保留的唯一整数是1和0,则可以有条件地执行FLD1
或FLDZ
。
通常,无符号或二进制补码格式的任何64位整数都可以用80位扩展精度浮点格式表示。可以使用零存储器访问将RAX
中找到的所有整数值加载到FPU堆栈上。这可以通过使用一系列x87算术指令来实现,这些指令可能在一个循环中执行,其行程数保存在GP寄存器中。一种方法是使用FADD
(对于负整数为FSUB
),直到st0
包含所需的整数值,尽管对于大(绝对)值来说这可能非常慢。对2的幂的整数有效的一种可能的优化方法是加载常数+1.0,使用FADD
将其加1以得到数字2,然后使用FMUL
直到达到所需的2的幂。在某些情况下可能更快的另一种方法是首先分解RAX
中的整数,使用FADD
构造每个素数,然后使用FMUL
乘以素数。
所有这些说明在所有Intel和AMD x86处理器上均受支持。
我认为您实际上想要Long latency instruction其中movd
/movq
+ sqrtss
或sqrtsd
比??更容易工作-> fsqrt。
fcmovcc
通过整数标志将整数依赖关系耦合到x87依赖关系>>而不是通过传输位模式来完成。在Skylake上,这是4位指令,但在4位ALU位。
在另一个方向上,fcmovcc
+ fcomi
setcc
或什至只是cmovcc
+ fcom
。正如@Hadi指出的那样,您可以使用fnstsw ax
(1 uop)或fldz
(2 uops)在x87寄存器中创建值。然后根据需要使用fld1
或类似名称将其设置为依赖。
[[可能的答案,因为它不太可能有用,所以还没有得到充分的研究] >>对您来说(可能涉及微码fcmovne st0, st1
:Skylake上为10 uops,Haswell上为31 uops。)
也许您可以使用emms
,然后使用movq mm0, rax
离开MMX状态
emms
,在当前的AMD上,FEMMS与EMMS相同,但我似乎还记得,以前的AMD CPU上的FEMMS并未定义x87寄存器。也许这对某些东西有用。它仍然设置标签词,因此未定义的内容可能仅与可能希望在EMMS之后找到AMD's 2018-may PDF ISA reference manual内容并再运行另一MMX指令的情况相关。或以mm0..7
状态查找数据。64位MMX寄存器别名80位x87寄存器的有效数(尾数)。
(我认为)。fxsave
堆栈映射到从x87状态字中的3位TOP字段索引的寄存器开始的那些基础80位寄存器。 (st0..7
用左轮手枪的枪管很好地描述了这一点。我不确定这是否真的可用,但是我不认为http://www.ray.masmcode.com/tutorial/fpuchap1.htm清除emms
/ st寄存器的内容,仅清除x87标签。 ([mm
说“将x87 FPU标记字中的所有标记的值设置为空(全1)”如果在EMMS指令重置x87 FPU标记字之前,浮点指令将x87 FPU数据寄存器堆栈中的一个寄存器加载,则会发生x87浮点寄存器堆栈溢出,从而导致x87浮点异常或错误结果。它只说“可以”,而不是“将”。也许在x87元数据处于已知状态的情况下,您可以将MMX指令和x87指令与某种一致的行为混合在一起吗?至少在特定的微体系结构上。
您无法读取标记字为Intel's vol.2 entry for
emms
(表示空)的x87寄存器,并且没有emms
,只有11
可以将单个标记字设置为funfree
(不会影响页首-stack指针或内容)。
您必须ffree
并修改已保存的x87状态元数据(包括32/64位模式下的填充在内的28个字节的标记字,然后再单击ffree
。
或者您可以为11
准备好一个预定义的x87“环境”,并将某些标记词设置为不使用。 (但是Agner Fog甚至没有安排该指令的时间。它显然将被微编码,并且可能很慢。)您可能可以在没有fstenv
的情况下使用它,但是它仍然是一个微编码的指令。
相关:fldenv
有一些我不久前挖出的关于fldenv
的链接,还有多少3dNow!可以与上交所互动。嗯,显然,它仍然会将标记字设置为所有未使用的字,但是并没有保留fldenv
和x87寄存器之间的已知映射。