查询遗留 3DNow!指令系统

Query about legacy 3DNow! instruction set

只是为了好玩,我正在查看 AMD 引入的 3DNow! set 中的遗留(已弃用)指令,并且我试图了解它们是如何使用的。所有指令似乎都按照这种模式编码:

instruction destination_MMn_register_operand, source_MMn_register_or_memory_operand

其中 destinationRegister = destinationRegister -操作- source

例如,pfadd mm0, mmword ptr [rcx] (0F 0F 01 9E):

将从 rcx 指向的内存中添加 2 个压缩浮点数到存储在 mm0 中的 2 个压缩浮点数并将结果保存在 mm0.

所以看起来那些 3DNow 指令总是有一个 mm 寄存器作为目的地。

但是您应该如何从这些 mm 寄存器中获取结果?

换句话说,没有 mov mmword ptr [rcx], mm0mov rax, mm0 指令。

其实还有,就是movdmovq。这些说明不是 3DNow! 的一部分,它们已经存在于 3DNow! 的 MMX 中。是对的扩展。这也是为什么 3DNow!包括一组看起来非常不完整的整数运算。

正如@harold所说,存储到内存已经被MMX movd覆盖,或者pshufw+movd只提取高float.

你不能做的一件事就是转动 3dNow!浮入一个没有 store/reload.

的 x87 80 位浮点数

可能有用的是 EMMS 的一个版本,它在 st0 中将 32 位 float 扩展为 80 位 x87 long double,同时设置 FPU回到 x87 模式而不是 MMX 模式1。或者甚至可以将多个 mm 寄存器转换为多个 x87 寄存器?

即这将是 movd dword [esp], mm0 / emms / fld dword [esp] 在 SIMD 减少后设置进一步标量 FP 的捷径。

记住这些是 IEEE754 float;您通常不希望它们出现在整数寄存器中,除非您要分离它们的位字段(例如,对于 explog 实现),但您可以使用 MMX shift/mask说明。


但是 movd 和 fld 很便宜,所以他们没有为了节省重新加载延迟而费心制作特殊指令。此外,作为单个指令实施可能会很慢。尽管 x86 不是 RISC ISA,但拥有一个真正复杂的指令通常比多个更简单的指令慢(尤其是在解码为多个 uops 完全是一回事之前。)例如Intel 和 AMD 的 sysentersyscall 指令替换 int 0x80 进行系统调用需要额外的指令 before/after 来保存更多状态,但总体上仍然更快。

3dNow! 的 femms leaves the MMX/3dNow! register contents undefined, only setting the tag words to unused instead of preserving the mapping from MMX registers to/from x87 register contents. See http://refspecs.linuxbase.org/AMD-3Dnow.pdf 官方 AMD 手册。 IDK 如果 AMD 的微体系结构只是删除了寄存器重命名信息或什么,但可能使存储/femms/x87 加载的快速方式节省了大量晶体管。

甚至 FEMMS 仍然有些慢,因此他们不想鼓励编码人员 leave/re-enter MMX/3dNow!经常模式。


有趣的事实:3dNow! PREFETCHW(带写意图的预取)仍在使用,并且有自己的 CPUID 功能位。

查看我在 What is the effect of second argument in _builtin_prefetch()?

上的回答

Intel CPU 很快就添加了将其解码为 NOP 的支持(因此像 64 位 Windows 这样的软件可以在不检查的情况下使用它),但 Broadwell 和后来实际上使用 RFO 进行预取以获取缓存行MESI Exclusive 状态,而不是 Shared,因此它可以在没有额外的 off-core 流量的情况下切换到 Modified。

CPUID 特征位表明它真的会预取。


脚注 1:

请记住,MMX 寄存器是 x87 寄存器的别名,因此不需要新的 OS 支持来 save/restore 上下文切换的体系结构状态。直到 SSE that we got new architectural state. So it wasn't until SSE2+3dNow! that a 3dNow! float to SSE2 double could make sense without switching back to x87 mode. And you could movq2dq xmm0, mm0 + cvtps2pd xmm0, xmm0.

他们可以在 mm 寄存器中有一个 float->double,但是 fld / fst 硬件只为 floatdouble->80 位和 80 位->floatdouble。而且用例是有限的;如果您使用的是 3dNow!,请坚持使用 float.