我可以理解旧的 PPC RISC 系统甚至 x86-64 的这种要求,但是对于旧的久经考验的 x86 呢?在这种情况下,堆栈只需在 4 字节边界上对齐。是的,一些 MMX/SSE 指令需要 16 字节对齐,但如果这是被调用方的要求,那么它应该确保对齐是正确的。为何负担 每一个 有此额外要求的呼叫者?这实际上可能会导致性能下降,因为每个调用站点都必须管理此要求。我错过了什么吗?

更新: 经过对此进行更多调查并咨询一些内部同事后,我对此有一些理论:

  1. PPC、x86 和 x64 版本操作系统之间的一致性
  2. 看来 GCC 代码生成器现在始终执行 sub esp,xxx,然后将数据“mov”到堆栈上,而不是简单地执行“push”指令。在某些硬件上这实际上可能更快。
  3. 虽然这确实使调用站点变得有点复杂,但当使用调用者清理堆栈的默认“cdecl”约定时,几乎没有额外的开销。

我对最后一项的问题是,对于依赖于被调用者清理堆栈的调用约定,上述要求 真的 “丑化”代码生成器。例如,某些编译器决定为自己的内部使用实现更快的基于寄存器的调用样式(即不打算从其他语言或源调用的任何代码)?这种堆栈对齐可能会抵消通过在寄存器中传递某些参数而获得的一些性能增益。

更新: 到目前为止,唯一真正的答案是一致性,但对我来说,这个答案有点太简单了。我在 x86 架构方面拥有 20 多年的经验,如果一致性、而不是性能或其他具体的东西才是真正的原因,那么我恭敬地建议开发人员要求它有点天真。他们忽视了近三十年的工具和支持。特别是如果他们期望工具供应商能够快速轻松地调整他们的工具以适应他们的平台(也许不是......它 苹果...)而不必跳过几个看似不必要的障碍。

我会再过一天左右再讨论这个主题,然后关闭它......

有关的

有帮助吗?

解决方案

来自《Intel®64 和 IA-32 架构优化参考手册》,第 4.4.2 节:

“为了获得最佳性能,流式 SIMD 扩展和流式 SIMD 扩展 2 要求其内存操作数与 16 字节边界对齐。与对齐的数据相比,未对齐的数据可能会导致严重的性能损失。”

来自附录 D:

“重要的是要确保堆栈帧在函数入口处与 16 字节边界对齐,以在整个函数调用过程中保持本地 __m128 数据、参数和 XMM 寄存器溢出位置对齐。”

http://www.intel.com/Assets/PDF/manual/248966.pdf

其他提示

我不确定,因为我没有第一手证据,但我相信原因是上交所。如果您的缓冲区已经在 16 字节边界上对齐(movps 与 movups),则 SSE 会快得多,并且任何 x86 至少有 sse2(适用于 mac os x)。它可以由应用程序用户来处理,但成本相当高。如果在 ABI 中强制执行此操作的总体成本不是太大,那么可能是值得的。SSE 在 mac os X 中使用相当普遍:加速框架等...

我相信这是为了使其与 x86-64 ABI 保持一致。

首先,请注意,16 字节对齐是 Apple 在 System V IA-32 ABI 中引入的一个例外。

仅在调用系统函数时才需要堆栈对齐,因为许多系统库正在使用需要 16 字节对齐的 SSE 或 Altivec 扩展。我在中找到了明确的参考 libgmalloc 手册页.

您可以按照您想要的方式完美地处理堆栈帧,但是如果您尝试使用未对齐的堆栈调用系统函数,您最终会得到一个 未对齐的堆栈错误 信息。

编辑:作为记录,您可以使用 GCC 编译时消除对齐问题 mstack 重新对齐 选项。

这是一个效率问题。

确保使用新 SSE 指令的每个函数中的堆栈都是 16 字节对齐,这会增加使用这些指令的大量开销,从而有效降低性能。

另一方面,始终保持堆栈 16 字节对齐可确保您可以自由使用 SSE 指令,而不会造成性能损失。这样做没有任何成本(至少在说明中衡量成本)。它只涉及更改函数序言中的常量。

浪费堆栈空间很便宜,它可能是缓存中最热的部分。

我的猜测是苹果相信每个人都只是使用 XCode (gcc) 来为你对齐堆栈。因此,要求堆栈对齐以便内核不必对齐只是一种微观优化。

虽然我无法真正回答您的“为什么”问题,但您可能会发现以下站点上的手册很有用:

http://www.agner.org/optimize/

关于 ABI,请特别查看:

http://www.agner.org/optimize/calling_conventions.pdf

希望这有用。

嗯,OS X ABI 不是也做了一些有趣的 RISC 之类的事情,比如在寄存器中传递小结构吗?

这表明与其他平台理论的一致性。

想想看,FreeBSD 系统调用 api 也对齐 64 位值。(例如lseek 和 mmap)

为了保持内核的一致性。这允许同一内核在多个体系结构上启动而无需修改。

不知道为什么没有人考虑过从传统的基于 PowerPC 的平台轻松移植的可能性?

读这个:

http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/100-32-bit_PowerPC_Function_Calling_Conventions/32bitPowerPC.html#//apple_ref/doc/uid/TP40002438-SW20

然后放大到“32位PowerPC函数调用约定”,最后是这样的:

“这些是32位PowerPC环境中可用的嵌入对齐方式:

电源对齐模式派生自 用于 AIX 操作系统的 IBM XLC 编译器。这是默认的 AIX 上使用的 GCC 的 PowerPC 体系结构版本的对齐方式 和 Mac OS X。因为这种模式最有可能是兼容的 在来自不同供应商的 PowerPC 架构编译器之间,它是 通常用于在不同 程序。

鉴于 OSX 传统的基于 PowerPC 的背景,可移植性是一个主要考虑因素 - 它要求始终遵循 AIX 的 XLC 编译器的约定。当您考虑需要确保所有工具和应用程序能够以最少的返工协同工作时,我认为尽可能坚持相同的遗留 ABI 非常重要。

这给出了哲学,进一步阅读是明确提到的规则(“Prolog 和 Epilog”):

所谓的功能负责分配自己的堆栈框架,并确保在堆栈中保留16个字节对齐。此操作由一段名为 prolog,编译器将其放在子例程的主体之前。在子例程的主体之后,编译器将 epilog 放在 将处理器还原到子例程之前的状态 叫。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top