【问题标题】:Why doesn't the Windows x64 calling convention use XMM registers to pass more than 4 integer args?为什么 Windows x64 调用约定不使用 XMM 寄存器来传递超过 4 个整数参数?
【发布时间】:2011-06-08 06:21:21
【问题描述】:

(微软)x64 calling convention 声明:

参数在寄存器 RCX、RDX、R8 和 R9 中传递。如果参数是浮点数/双精度数,则在 XMM0L、XMM1L、XMM2L 和 XMM3L 中传递。

这很好,但为什么只是浮动/双打?为什么整数(可能还有指针)也不通过 XMM 寄存器传递?
似乎有点浪费可用空间,不是吗?

【问题讨论】:

  • 我在后面的问题上写了一个更完整的答案:Why not store function parameters in float registers?。你介意编辑标签以包含x86-64 和/或assembly,这样我就可以重复这个了吗?
  • @PeterCordes:但是这个是 4 年前来的……?!另外,在我的问题中,我并不是真的打算将指针伪装成非指针,反之亦然。另一张海报实际上打算将它们伪装成不同的类型,所以这不是同一个问题......我可以想象,例如在这种情况下禁止优化。
  • 稍后的规范可以是一个很好的 dup 目标,以清理同一问题的早期分散问题。这基本上就是这里发生的事情,但我不是故意写它的目的是为了成为一个规范,只是回答这个问题。我在另一个问题中没有看到任何关于在 C 中使用浮点/双精度来实现这一点的内容,只是问(就像你一样)为什么 XMM regs 不用于传递整数/指针 arg 类型。 (他们说“浮点寄存器”而不是 XMM 寄存器,但这仍然是一个调用约定设计问题,而不是破解 C 来解决它。)
  • 无论您是否同意以 dup 身份关闭,这个问题仍然缺少 x86-64 标记。 (我宁愿不编辑自己,以防我 能够说服您这是重复的。)
  • @PeterCordes:不是“在 C 中”。但是“使用浮点寄存器来存储下一个参数,即使参数不是单/双精度变量” 正是提出了类型双关语的等价物。再说一次,我不认为这是我在这个问题中的意图(当然不仅仅是来自文本),所以我不同意两者都是对方的欺骗。人们可以不同意该问题中的提案,但不能不同意这一问题。 (对于标签本身,如果您继续添加它,您可能会比我们都浪费的争论节省更多的时间。我不同意这是 x86-64。)

标签: windows assembly x86-64 sse calling-convention


【解决方案1】:

因为大多数对非 FP 值(即整数和地址)的操作都设计为使用通用寄存器。

有整数 SSE 运算,但它们只是算术运算。

因此,如果调用约定支持通过 SSE 寄存器传递整数和地址,则几乎总是需要将值复制到通用寄存器。

【讨论】:

  • 但这不是比可能溢出到堆栈上更好吗?
  • IIRC,没有在GP寄存器和SSE寄存器之间移动数据的操作。这意味着通过 SSE reg 传递数据。需要(在最坏的情况下)将值复制到内存(最好对齐)两次。这比使用堆栈要糟糕得多。顺便说一句,一些 CPU 供应商将堆栈映射到寄存器文件,因此堆栈访问变得更便宜。不过,不知道是英特尔还是 AMD 这样做。
  • +1 我完全不知道这个^事实,这解释了很多。 :) 谢谢!
  • @Mehrdad:不,x86 非常擅长存储/重新加载,具有高效的存储转发(如 5c 延迟)。有movq xmm, r64movq r64, xmm,但吞吐量比负载差。不过,延迟更好。此外,如果您想在使用它之前调用另一个函数,那么您不必再次将 arg 安全地保存在内存中。
【解决方案2】:

函数通常希望使用整数参数指针(作为索引或计算结束指针作为循环边界),或与GP寄存器中的其他整数参数一起使用。或者从内存中加载的其他整数,他们想在 GP 寄存器中使用

您不能有效地将 XMM reg 中的整数用作循环计数器或边界,因为没有为分支指令设置整数标志的压缩整数比较。 (pcmpgtd 创建 0/-1 个元素的掩码)。

另请参阅Why not store function parameters in XMM vector registers? 和此处的其他答案了解更多信息。


但除此之外,这种设计理念甚至不是 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 整数 regs 来保存寄存器参数的最大数量已经,即使它们都是整数。


(与 x86-64 System V 不同,其中前最多 8 个 FP args 在 xmm0..7 中传递,而不管使用了多少整数/指针 arg 传递寄存器。)

Why does Windows64 use a different calling convention from all other OSes on x86-64?

【讨论】:

    猜你喜欢
    • 2014-04-21
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多