为什么不将函数参数存储在 XMM 向量寄存器中?

Why not store function parameters in XMM vector registers?

我正在读这本书:"Computer Systems - A Programmers Perspective"。我发现,在 x86-64 架构上,我们被限制为 6 个整数参数,这些参数将被传递给寄存器中的函数。下一个参数将在堆栈上传递。

而且,第一个最多 8 个 FP 或矢量参数在 xmm0..7 中传递。

为什么不使用浮点寄存器来存储下一个参数,即使参数不是 single/double 精度变量?

将数据存储在寄存器中(据我所知)比将其存储到内存中然后从内存中读取要高效得多。

我认为这不是个好主意,因为:

  1. 您不能将 FPU/SSE 寄存器用作通用寄存器。我的意思是,此代码不正确 (NASM):

    mov byte[st0], 0xFF
    
  2. 如果比较发送数据to/fromFPU/SSE和通用registers/memory,FPU/SSE很慢

编辑:记住,我可能不对。

大多数函数的整数参数不超过 6 个,因此这确实是一种极端情况。在 xmm 寄存器中传递一些多余的整数参数会使查找浮点参数的规则更加复杂,几乎没有任何好处。除了它可能 不会 使代码更快这一事实之外。

在内存中存储多余参数的另一个原因是您的函数可能不会立即使用它们。如果你想调用另一个函数,你必须将那些参数从 xmm 寄存器保存到内存,因为你调用的函数会破坏任何参数传递寄存器。 (无论如何,所有 xmm regs 都是调用者保存的。)因此,您最终可能会得到将参数填充到不能直接使用的向量寄存器的代码,并在调用另一个函数之前从那里将它们存储到内存中,并且仅然后 将它们加载回整数寄存器。或者即使该函数不调用其他函数,它也可能需要向量寄存器供自己使用,并且必须将参数存储到内存中以释放它们以用于 运行ning 向量代码!将 push 参数放到堆栈上会更容易,因为 push 非常优化,出于明显的原因,在一个 uop 中完成存储和 RSP 的修改,大约和mov.

SysV Linux/Mac x86-64 ABI (r11) 中有一个整数寄存器不用于参数传递,但也不调用保留。在不保存的情况下使用惰性动态链接器代码的临时寄存器很有用(因为此类垫片函数需要将其所有参数传递给动态加载函数)和类似的包装函数。

所以 AMD64 可以为函数参数使用更多的整数寄存器,但前提是调用函数在使用前必须保存的寄存器数量。 (或者对于不使用 "static chain" 指针等语言的双用途 r10。)

无论如何,在寄存器中传递的参数越多并不总是越好。


xmm 寄存器不能用作指针或索引寄存器,将数据从 xmm 寄存器移回整数寄存器比加载数据更能减慢周围代码的速度刚刚存储。 (如果任何执行资源将成为瓶颈,而不是缓存未命中或分支预测错误,它更有可能是 ALU 执行单元,而不是 load/store 单元。将数据从 xmm 移动到 gp 寄存器需要一个 ALU uop,在英特尔和 AMD 当前的设计中。)

L1 缓存非常快,存储 -> 负载转发使得内存往返的总延迟大约为 5 个周期,例如英特尔哈斯韦尔。 (像 inc dword [mem] 这样的指令的延迟是 6 个周期,包括一个 ALU 周期。)

如果将数据从 xmm 移动到 gp 寄存器是 all 你要做的(没有其他事情可以让 ALU 执行单元忙碌),那么是的,在 Intel CPU 上movd xmm0, eax/movd eax, xmm0(2 个 Intel Haswell 周期)的往返延迟小于 mov [mem], eax/mov eax, [mem](5 个 Intel Haswell 周期)的延迟,但整数代码通常是不像 FP 代码那样完全受到延迟的瓶颈。

在 AMD Bulldozer 系列 CPU 上,两个整数内核共享一个 vector/FP 单元,直接在 GP regs 和向量 regs 之间移动数据实际上非常慢(一种方式 8 或 10 个周期,或者一半压路机)。一个内存往返只有8个周期。

32 位代码设法 运行 相当好,即使 所有 参数都在堆栈上传递,并且必须加载。 CPU 针对将参数存储到堆栈然后再次加载它们进行了高度优化,因为笨拙的旧 32 位 ABI 仍然用于 lot 代码,尤其是。在 Windows 上。 (大多数 Linux 系统主要是 运行 64 位代码,而大多数 Windows 桌面系统 运行 很多 32 位代码,因为很多 Windows 程序只能作为预-编译的 32 位二进制文​​件。)

参见 http://agner.org/optimize/ for CPU microarchitecture guides to learn how to figure out how many cycles something will actually take. There are other good links in the wiki,包括上面链接的 x86-64 ABI 文档。