我有一个用LLVM编写的编译器,我正在寻找我的ABI遵从性。例如,我发现很难在Windows x86或Linux上找到C ABI的规范文档。我找到的那些用RAX/EAX等术语来解释它,而不是我可以使用的IR术语。
到目前为止,我认为LLVM对聚合的处理是不可见的——也就是说,它将每个聚合的成员视为不同的参数。因此,例如,在Windows x64上,如果我想像文档所说的那样处理聚合,我需要强制转换为该大小的单个整数,如果8,16,32或64位。否则,通过指针传递
对于Windows x86,似乎__cdecl和__stdcall不需要我的任何操作,因为所有参数都在堆栈上传递。__fastcall说前两个32位或更小的参数是寄存器传递的,所以我需要强制聚合这个或更小的大小。__thiscall将这个传递到寄存器中,其余的传递到堆栈中,所以看起来我不需要在这里执行任何调整。
对于__vectorcall,通过整数强制传递不超过sizeof(void*)的聚合。对于其他聚合,如果它们是hva,则按值传递;在x86上按值传递或在x64上按指针传递。
这看起来很简单(相对而言),但是对于sext
的LLVM文档清楚地声明"这向代码生成器表明,参数或返回值应该由调用者(对于参数)或被调用者(对于返回值)进行符号扩展,以达到目标ABI(通常是32位)所要求的程度。"微软关于x86调用约定的页面没有提到将任何东西扩展到任何宽度。
我观察了Clang生成的LLVM IR,它在Windows上生成byval
属性。我从上面收集到的理解从来没有要求byval
的使用。
我如何将各种平台C abi降低到LLVM IR?
我不能说我100%理解你的问题,但值得注意的是,LLVM IR根本不能代表平台abi的所有微妙之处。因此,在Clang工具链中,前端负责执行ABI降低,例如正确地将对象按值传递给函数等。
查看Clang源代码树中的lib/Basic/Targets.cpp
以获取其定义。详细信息见lib/CodeGen/TargetInfo.cpp
我最终破解了Clang的CodeGen内部来为我执行C ABI调用(c++ ABI支持已经完成)。因此,我不必重新实现(和重新测试)他们的代码,而是简单地重用了他们的工作。官方的CodeGen api不是公开的,也不打算被任何人使用,但在这种情况下,我设法使它工作。事实证明,它没有看起来那么可怕-许多类,如LValue/RValue/ReturnValueSlot只是llvm::Value*的包装,并附加了一些额外的可选语义。
更多的问题将是创建从C ABI到我自己的ABI的蹦床。CodeGenFunction接口似乎不太适合这种情况。但是我想我可以做到。