我们应得的 Rust 调用约定 · mcyoung

主要观点:Rust 的所谓“C ABI”不佳,在有效传递复杂类型方面缺乏想象力。介绍了通过-Zcallconv来改变extern "Rust"的调用约定,可将其设置为legacyfastfast调用约定可更好地利用寄存器传递参数等。还详细说明了如何通过一系列步骤让 LLVM 按照期望传递参数,以及在 Rust 中处理结构体、联合等类型的方式,包括根据有效大小分配寄存器、处理枚举等。同时提到 Rust 可利用优化依赖的 ABI 进行更极端的优化,如丢弃未使用参数等,且介绍了一些相关的注意事项和可能的改进方向。

关键信息:

  • Rust 现用 LLVM 的内置 C 调用约定,生成的代码在简单函数时不佳。
  • extern "Rust"可通过-Zcallconv设置调用约定,fast调用约定可更好利用寄存器。
  • 确定目标平台可通过寄存器传递的最大数值等步骤来让 LLVM 按期望传递参数。
  • Rust 中处理结构体、联合等类型时要根据有效大小分配寄存器等。
  • Rust 可利用优化依赖的 ABI 进行更优的优化,如丢弃未使用参数等。

重要细节:

  • 在 x86 上,-Zcallconv=fast函数签名通常为特定格式,通过poison语义可避免额外工作。
  • Rust 中返回值按有效大小处理,大于输出寄存器空间的转为 by-ref 返回。
  • 处理枚举时用适当的判别式-联合对替换,处理联合时根据情况选择传递方式。
  • 对于复杂的 Rust 函数,如do_thing,展示了处理前后的 LLVM IR 及代码变化。
  • 优化依赖的 ABI 可根据函数体情况优化参数传递等,如HashMap::get()可避免不必要的内存流量。
阅读 16
0 条评论