我有一个用 LLVM 编写的编译器,我正在寻找我的 ABI 合规性。例如,我发现实际上很难在 Windows x86 或 Linux 上找到 C ABI 的规范文档。我发现的那些是用 RAX/EAX/etc 来解释的,而不是我可以使用的 IR 术语。
到目前为止,我想我已经发现 LLVM 以不可见的方式处理聚合——也就是说,它将它们的成员各自视为一个不同的参数。因此,例如,在 Windows x64 上,如果我想处理文档所说的聚合,我需要强制转换为该大小的单个整数,如果是 8、16、32 或 64 位。否则,按指针传递。
对于 Windows x86,似乎 __cdecl 和 __stdcall 不需要我的任何操作,因为所有参数都在堆栈上传递。__fastcall 表示前两个 32 位或更小的参数是寄存器传递的,所以我需要强制该大小或更小的聚合。__thiscall 在寄存器中传递这个,其余的在堆栈中,所以看起来我不需要在这里执行任何调整。
对于 __vectorcall,通过整数强制传递不超过 sizeof(void*) 的聚合。对于其他聚合,如果它们是 HVA,则按值传递;否则在 x86 上按值传递或在 x64 上按指针传递。
这看起来很简单(好吧,相对而言),但 LLVM 文档sext
明确指出“这向代码生成器表明参数或返回值应符号扩展至目标 ABI 所需的范围(通常为 32 位)由调用者(对于参数)或被调用者(对于返回值)。”。x86 调用约定的 Microsoft 页面没有提到将任何内容扩展到任何宽度。
而且我观察到 Clang 生成的 LLVM IRbyval
在 Windows 上生成属性。我从上面收集到的理解从来不需要byval
' 的用法。
如何将各种平台 C ABI 降低到 LLVM IR?