【发布时间】:2016-03-16 22:52:52
【问题描述】:
我对 MOVSD 汇编指令感到困惑。我写了一些数字代码来计算一些矩阵乘法,只是使用没有 SSE 内在函数的普通 C 代码。我什至不包括用于编译的 SSE2 内在函数的头文件。但是当我检查汇编输出时,我看到了:
1) 使用128位向量寄存器XMM; 2) SSE2指令MOVSD被调用。
我知道 MOVSD 本质上是在单双精度浮点上运行的。它只使用XMM寄存器的低64位,将高64位设置为0。但我只是不明白两件事:
1) 我从来没有给编译器任何使用 SSE2 的提示。另外,我使用的是 GCC 而不是英特尔编译器。据我所知,intel 编译器会自动寻找向量化的机会,但 GCC 不会。那么 GCC 是如何知道使用 MOVSD 的呢?或者,这条 x86 指令是否早在 SSE 指令集之前就已经存在,而 SSE2 中的 _mm_load_sd() 内部函数只是为了提供向后兼容,以便使用 XMM 寄存器进行标量计算?
2) 为什么编译器不使用其他浮点寄存器,无论是80位浮点堆栈,还是64位浮点寄存器?为什么必须使用 XMM 寄存器(通过设置高 64 位 0 并实质上浪费该存储空间)来付出代价? XMM 是否提供更快的访问?
顺便说一句,我还有一个关于 SSE2 的问题。我只是看不出 _mm_store_sd() 和 _mm_storel_sd() 之间的区别。两者都将低 64 位值存储到一个地址。有什么区别?性能差异??对齐差异??
谢谢。
更新 1:
好的,很明显,当我第一次问这个问题时,我缺乏一些关于 CPU 如何管理浮点运算的基本知识。所以专家们倾向于认为我的问题是无意义的。由于我什至没有包含最短的示例 C 代码,因此人们可能也会认为这个问题含糊不清。在这里,我将提供a review 作为答案,希望对任何不清楚现代 CPU 上的浮点运算的人有用。
【问题讨论】:
-
在 64 位模式下,调用约定已经要求 SSE 寄存器用于浮点参数和返回值。由于 SSE 寄存器不是以堆栈形式组织的,而且它们的数量更多,因此编译器更容易使用。有标量 SSE 指令。此外,有趣的是,您担心会浪费其中一半的空间 - 如果您根本不使用它们,所有它们都会浪费;)
-
没有 64 位浮动指针寄存器。只有 80 位浮点堆栈和 XMM 寄存器。 MOVSD 指令是标量指令,而不是向量指令,因此它的使用并不意味着自动向量化。
-
那些不是浮点寄存器。
-
好的,
_mm_storel_pd生成MOVLPD指令,而_mm_store_sd生成MOVSD。在写入内存时,它们具有相同的功能。至少我看不出区别。 -
@Jester:AFAICT,
movlpd和movsd都存在的唯一原因是编码的一致性/规律性:movlps与movss不同,所以这两个指令都已经存在。 SSE2 对double使用具有不同转义字节的相同操作码,而不是single版本。 (movlpd与每个 CPU 上的movlps相比,已经只是浪费了指令字节,因为 AFAIK 没有 CPU 关心任何数据移动 insns 的单版本和双版本。英特尔一直通过始终使单与双版本相比,直到vextractf128和其他东西)
标签: c assembly x86-64 sse sse2