(Microsoft) x64 调用约定指出:
参数在寄存器 RCX、RDX、R8 和 R9 中传递。如果参数是浮点/双精度,则它们在 XMM0L、XMM1L、XMM2L 和 XMM3L 中传递。
这很好,但为什么只是浮动/双打?为什么整数(也可能是指针)不通过 XMM 寄存器传递?
似乎有点浪费可用空间,不是吗?
因为大多数对非 FP 值(即整数和地址)的操作都设计为使用通用寄存器。
有整数 SSE 运算,但它们只是算术运算。
因此,如果调用约定支持通过 SSE 寄存器传递整数和地址,则几乎总是需要将值复制到通用寄存器。
函数通常希望将整数 args与指针(作为索引或计算端点作为循环边界)一起使用,或者与 GP 寄存器中的其他整数 args 一起使用。或者从内存中加载的其他整数,他们想在 GP 寄存器中使用
您不能有效地将 XMM reg 中的整数用作循环计数器或绑定,因为没有为分支指令设置整数标志的压缩整数比较。(pcmpgtd
创建 0/-1 个元素的掩码)。
另请参阅 为什么不在 XMM 向量寄存器中存储函数参数?和其他答案在这里更多。
但即便如此,这种设计理念甚至不是 Windows x64 fastcall / vectorcall 的选项。
Windows x64 故意选择浪费空间来简化可变参数函数。可以将寄存器 args 转储到返回地址上方的 32 字节“影子空间”/“家庭空间”中,形成一个 args 数组。
这就是(例如)Windows x64 传递 R8 或 XMM2 中的第三个参数的原因,而不管早期参数的类型如何。以及为什么对可变参数函数的调用还需要将 FP args 复制到相应的整数寄存器,因此函数序言可以转储 arg regs,而无需弄清楚哪些可变参数 args 是 FP 哪些是整数。
为了使 arg-array 工作正常,寄存器中只能传递 4 个 args,无论您是否混合使用整数和 FP args。 已经有足够的 GP 整数 reg 来保存最大数量的寄存器 args,即使它们都是整数。
(与 x86-64 System V 不同,其中第一个最多 8 个 FP 参数在 xmm0..7 中传递,而不管使用了多少整数/指针参数传递寄存器。)