正如@harold 所说,MMX movd 或pshufw+movd 已经涵盖了存储到内存中以仅提取高位float。
您不能做的一件事就是打开 3dNow!在没有存储/重新加载的情况下浮动到 x87 80 位浮点数。
可能有用的是一个 EMMS 版本,它将 32 位 float 扩展为 80 位 x87 long double in st0,同时将 FPU 设置回 x87 模式而不是 MMX 模式1。或者甚至可以将多个 mm 寄存器放入多个 x87 寄存器中?
即这将是movd dword [esp], mm0 / emms / fld dword [esp] 在 SIMD 减少后设置进一步标量 FP 的捷径。
记住这些是IEEE754 floats;您通常不希望它们在整数寄存器中,除非您要分离它们的位域(例如,对于 exp 或 log 实现),但您可以使用 MMX 移位/屏蔽指令来做到这一点。
但是 movd 和 fld 很便宜,所以他们没有费心去做一个特殊的指令来节省重新加载延迟。此外,作为单条指令实施可能会很慢。尽管 x86 不是 RISC ISA,但拥有一条非常复杂的指令通常比多条更简单的指令慢(尤其是在完全解码为多个微指令之前。)例如Intel 和 AMD 的 sysenter 和 syscall 指令用于替换系统调用的 int 0x80 需要在之前/之后附加指令以保存更多状态,但总体上仍然更快。
3dNow! 的femms leaves the MMX/3dNow! register contents undefined,仅将标记字设置为未使用,而不是保留从 MMX 寄存器到/从 x87 寄存器内容的映射。有关 AMD 官方手册,请参阅 http://refspecs.linuxbase.org/AMD-3Dnow.pdf。 IDK 如果 AMD 的微架构刚刚删除了寄存器重命名信息或其他什么,但可能使 store / femms / x87-load 成为快速方式可以节省大量晶体管。
甚至 FEMMS 仍然有些慢,所以他们不想鼓励编码人员离开/重新进入 MMX/3dNow!经常模式。
有趣的事实:3dNow! PREFETCHW(带有写入意图的预取)仍在使用,并且有自己的 CPUID 功能位。
在What is the effect of second argument in _builtin_prefetch()?上查看我的回答
Intel CPU 很快增加了对将其解码为 NOP 的支持(因此 64 位 Windows 之类的软件可以在不检查的情况下使用它),但 Broadwell 和后来实际上使用 RFO 预取以使缓存行处于 MESI Exclusive 状态,而不是共享,因此无需额外的核心流量即可翻转到已修改。
CPUID 特性位表示它确实会预取。
脚注 1:
请记住,MMX 寄存器是 x87 寄存器的别名,因此不需要新的操作系统支持来保存/恢复上下文切换时的架构状态。直到SSE,我们才获得了新的架构状态。所以直到SSE2+3dNow!那是一个 3dNow! float 到 SSE2 double 在不切换回 x87 模式的情况下可能有意义。你可以movq2dq xmm0, mm0 + cvtps2pd xmm0, xmm0。
他们本可以在 mm 寄存器中有一个 float->double,但 fld / fst 硬件仅适用于 float 或 double->80 位和 80 位- >float 或double。并且用例是有限的;如果您使用的是 3dNow!,请坚持float。