查询旧版 3DNow!指令系统
Posted
技术标签:
【中文标题】查询旧版 3DNow!指令系统【英文标题】:Query about legacy 3DNow! instruction set 【发布时间】:2018-08-06 20:47:32 【问题描述】:只是为了好玩,我正在查看 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], mm0
或mov rax, mm0
指令。
【问题讨论】:
【参考方案1】:正如@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 float
s;您通常不希望它们在整数寄存器中,除非您要分离它们的位域(例如,对于 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
。
【讨论】:
感谢您的信息。很有意思。顺便说一句,我在阅读 AMD 文档(在我的答案中链接)后注意到,它们将用于 3Dnow 指令的单精度浮点数称为具有 24 位有效数。但据我了解,英特尔传统的 32 位浮点数使用 23 位尾数。 3Dnow 的打包浮点数是否使用与英特尔不同的浮点格式? @MikeF:我不这么认为。几乎可以肯定只是一个术语问题; AMD 正在计算有效数字中的隐含位。***有一篇很好的文章 (en.wikipedia.org/wiki/…) 将 IEEE binary32 描述为 24 位精度,23 位存储。 (对于次正规数,有效数的第一位是 0,而不是通常的 1。所以全零或非指数意味着前导位。)顺便说一句,“有效数”是首选术语,但尾数更广泛使用.是一样的。 哦,好的。我只是好奇而已。谁知道,AMD 可能已经发明了他们自己的浮点格式。不过此时这并不重要,因为无论如何 3DNow 几乎 99% 都死了。我认为唯一剩下的就是prefetchw
指令。 Windows uses it 几乎每个内核模式调用都在那里预加载一些内核结构。至于您指出的FEMMS
指令,我认为它只是AMD。在我所有的英特尔系统上都是#UD'ing。
@MikeF:是的,femms
是 3dNow! 的一部分,并没有被用作 MMX/SSE 扩展。我提到它是因为 CPU 供应商设计他们的指令集扩展以方便他们自己当前的微架构。 (另一个例子:英特尔的 SSE cvtsi2ss xmm0, eax
未修改 XMM0 的高位字节,可能因此它可以是 Pentium III 上的单个 uop,它将 128 位向量操作分成 2。但是这种短视的错误依赖导致gcc 首先选择pxor xmm0,xmm0
,以避免创建循环承载的 dep 链或耦合到慢速 dep 链的风险。
哦,彼得,也是要提起的。英特尔是否支持prefetch
指令(没有获取“写入”的指令)?看起来它是仅限 AMD 的,是 3Dnow 集的遗产,但英特尔文档对此却出奇地沉默。【参考方案2】:
其实有,即movd
和movq
。这些指令不是 3DNow! 的一部分,它们已经存在于 3DNow! 的 MMX 中。是对。这也是为什么 3DNow!包括一组看起来非常不完整的整数运算。
【讨论】:
以上是关于查询旧版 3DNow!指令系统的主要内容,如果未能解决你的问题,请参考以下文章
极客日报:小鹏汽车回应非法收集人脸数据被罚10万;OPPO发布首颗自研芯片马里亚纳X;AMD 3DNow指令集被Linux淘汰
Linux系统理论操作学习25History 历史指令回溯 查找之前的指令,history命令参数设置