查询旧版 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], mm0mov rax, mm0 指令。

【问题讨论】:

【参考方案1】:

正如@harold 所说,MMX movdpshufw+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;您通常不希望它们在整数寄存器中,除非您要分离它们的位域(例如,对于 explog 实现),但您可以使用 MMX 移位/屏蔽指令来做到这一点。


但是 movd 和 fld 很便宜,所以他们没有费心去做一个特殊的指令来节省重新加载延迟。此外,作为单条指令实施可能会很慢。尽管 x86 不是 RISC ISA,但拥有一条非常复杂的指令通常比多条更简单的指令慢(尤其是在完全解码为多个微指令之前。)例如Intel 和 AMD 的 sysentersyscall 指令用于替换系统调用的 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 硬件仅适用于 floatdouble->80 位和 80 位- >floatdouble。并且用例是有限的;如果您使用的是 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】:

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

【讨论】:

以上是关于查询旧版 3DNow!指令系统的主要内容,如果未能解决你的问题,请参考以下文章

指令集的相关问题!

`-march` 和指令集开关之间会不会有冲突?

极客日报:小鹏汽车回应非法收集人脸数据被罚10万;OPPO发布首颗自研芯片马里亚纳X;AMD 3DNow指令集被Linux淘汰

Linux系统理论操作学习25History 历史指令回溯 查找之前的指令,history命令参数设置

linux基本指令的使用。cdls文件查看wc历史命令调命令用法查询通配符

Suse linux查询内存大小的指令是啥?