使用 RSI/RDI vs r8-r15(速度优化)

Using RSI/RDI vs r8-r15 (speed optimization)

我想尽可能地优化我的函数,我所做的其中一件事就是使用 r8 作为指针,因为这是指针在 x64 函数中被推入的寄存器。

但是推动 RSI 或 RDI,将指针移动到它们并稍后在循环中使用它们会更快吗?

例如, mov [RSI],DL ;将符合 2 个字节 和: mov [r8],DL ;将符合 3 个字节

所以,如果我循环 100 到 200 次,r8 会不会因为要解码的额外字节而变慢?或者推动 RSI 并移动指针是否会消除任何可能的速度增加?显然 push 和 mov 会发生在循环之外。

取决于CPU。通常平均指令大小为 4 就可以避免前端瓶颈,即使在像 Core2 这样的旧 CPUs 上也是如此。

现代 CPU 像 Sandybridge 系列和 Ryzen 缓存解码 uops 并且对循环内的代码大小(或对齐)不那么敏感,仅在 L1i 和 uop 缓存足迹的大规模。

Nehalem 有一个 "loop buffer" 用于高达 28 微指令的小循环。 (SnB 家族也有这个,除了 Skylake/Kaby Lake,它被微代码更新禁用,所以它们 运行 甚至来自 uop 缓存的小循环)。 Core2 有一个最多 64 字节的预解码循环缓冲区。 (参见 Agner Fog 的指南)。


但是是的,一般来说,代码密度越高越好,因此支持指针和 32 位值的非 REX 寄存器,对始终需要 [= 的 64 位整数使用 r8-r15 66=]无论如何。但通常不值得花费额外的说明来实现这一点。 uop 计数通常比代码大小更重要,尤其是在循环中。

使用性能计数器进行分析以查明循环中是否存在任何前端瓶颈。如果是这样,请确保 saving/restoring 一些更低的 regs,如 RBP 并在你的函数中使用它们而不是 R8 是有用的。 (但请记住 [rbp] 实际上需要一个 disp8=0,[rbp+0]。)

延伸阅读:

  • x86 tag wiki
  • 中的性能链接
  • Agner Fog's 现代 Intel 和 AMD 的优化指南和微架构指南 CPUs
  • Intel和AMD自己的优化手册。 (x86 标签 wiki 中的链接)
  • Stack Overflow 上的 x86 性能答案(其中很多是我的,但其他一些人发布了一些很棒的东西)

    • 很多关于中小型循环的细节,以及 uop 缓存与对齐
    • Branch alignment for loops involving micro-coded instructions on Intel SnB-family CPUs

    以及与循环无关的更一般的内容:

    • (and 对于其他 uarches)。由于您提到使用 DL.