【问题标题】:Can you add two 64-bit integers natively in x86?您可以在 x86 中本地添加两个 64 位整数吗?
【发布时间】:2019-04-14 15:35:55
【问题描述】:

x86 中的“常规”寄存器只有 32 位大小,因此您不能使用它们将两个 64 位整数相加(除非您分多个步骤进行相加)。

但是你能用另一种方式原生地添加两个 64 位整数吗,例如使用 SSE?

【问题讨论】:

  • 双指令序列算不算原生?如果是这样,几乎每个 CPU 都可以“本地”将任意大小的整数相加。
  • 几乎所有支持 SSE 的 CPU 也支持 64 位扩展(除了 2003-2004 年的一些 Intel 型号)。你到底在追求什么?
  • @SevaAlekseyev SSE 可以追溯到 1999 年的 Pentium III,而英特尔至少在 2008 年之前在其产品线中的 CPU 不支持 64 位(例如 Intel Core Solo/Duo CPU。)

标签: assembly x86 sse


【解决方案1】:

在 32 位模式下,有四种方法可以做到这一点:

  • 最推荐的方法是在通用寄存器上使用addadc 分两步进行加法
  • 如果你的 CPU 有一个 FPU,你也可以使用 x87 FPU 来做 64 位运算。由于 x87 FPU 包含 64 位尾数,因此只要不超过 64 位范围,对 64 位整数的计算是精确的。
  • 如果您的 CPU 至少支持 SSE2,您可以在 MMX 寄存器上进行 64 位运算
  • 如果您的 CPU 至少支持 SSE2,您还可以在 XMM 寄存器上进行 64 位运算

对于单个 64 位操作,其中最快的可能是 add/adc 方法。对于多个操作,SSE2 将是最快的,然后是 MMX(如果您可以忍受转换惩罚并且在 MMX 状态下无法使用 x87 FPU),最后是 x87。

在 64 位模式(长模式)下,您还可以简单地对 64 位通用寄存器进行 64 位运算。

如果您需要更多详细信息或示例,请告诉我。

【讨论】:

  • 如果您不需要整数寄存器中的结果,MMX 或 SSE2 paddd 非常便宜,并减少标量代码的寄存器压力。 add/adc 如果您想根据结果或其他东西进行分支显然很好,否则movq + paddd 非常棒,尤其是在 Intel Haswell 和更早版本上(adc 是 2 微秒)。而且通常您不希望现代英特尔上的内存目标adc,因此如果最终目标是内存而不是另一个 64 位操作,则需要 2 个存储指令。 MMX paddd 甚至可以使用 64 位内存源进行加法(如标量加法/adc)
  • @PeterCordes 如何使用 PADDD 实现 32 位加法之间的进位?还是您的意思是 PADDQ 指令?也不清楚 PADDD 或 PADDQ 实际上是 MMX 指令。尽管它们使用 MMX 寄存器,但似乎它们需要 SSE2:stackoverflow.com/a/13045166/3826372
  • @RossRidge:哎呀,是的,我想说的是 paddq,而不是 paddd。显然,有太多的“32”在我脑海中飞来飞去:/ 是的,paddq mm, mm/m64 在 Pentium 4 中添加了 SSE2,根据 Appendix B of the NASM manual,它列出了所有指令的所有形式的引入时间。使用paddd + pcmpgtd + shift 或其他东西来模拟 32 位进位是不值得的,但在具有 SSE2 的现代 CPU 上,使用 paddq mm0, [esp+4] 是一个合理的好选择,而不是 movq + @987654341 @,如果你能避免/摊销emms
  • 缺点:mov-elimination 仅适用于 xmm regs,而不适用于 mmx,并且 Skylake 在比等效 XMM 更少的端口上运行一些 MMX 指令。 (因为它通常被用于整数工作的 64 位模式整数寄存器和用于实际 SIMD 的 SSE* 淘汰。编译器很少将它用于 32 位模式中的标量。)而且 EMMS 不是免费的。
  • @PeterCordes 已修复!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多