按值传递结构,同时符合LLVM IR中的C调用约定



我想在C++和JIT的LLVM程序之间按值传递结构。我在SO上看到了很多关于这一点的讨论,甚至还有一些问题。我读到,如果我想让我的程序真正传递价值,我需要做一些叫做"论点强制"的事情。使用byvalsret看起来像是简单的跨平台解决方案。这仍然有点痛苦,C++代码必须记住传递指针而不是值(尽管调用代码是C++,所以我可以做一些模板魔术(。

我对这个问题读得越多,似乎就越不理解。调用约定是一个特定于平台的问题,应该由代码生成器来处理,对吧?我不明白为什么特定于平台的代码生成器不只是处理特定于平台处理结构的方式(同时符合平台的C ABI(。前端应该与平台无关!

有没有一个通行证可以强迫我进行辩论?访问每个函数声明和每个函数调用并转换所有结构以使其与平台的C ABI兼容的过程?我觉得这是所有前端都会使用的东西,如果它存在的话,而Clang没有使用它,所以也许这是不可能的。为什么这不是一个可行的解决方案?如果通行证可以处理这个问题,那么我希望它能成为LLVM的一部分。

我不明白为什么每个前端都要做论点胁迫。我甚至不知道如何进行论点胁迫。我见过一些例子,人们使用Clang代码生成代码,并分解出进行论点强制的部分。不幸的是,如果我想要真正的C ABI兼容性,这似乎是最好的解决方案。事实上,甚至可以将另一个前端的一部分重新用于完全不同的语言,这让我继续想知道为什么必须在前端进行?

对此必须采取措施!我们不能一直在每个前端编写相同的C ABI兼容性代码。太荒谬了!也许我就是不明白。

有人能帮我清理一下吗?我之所以考虑使用byvalsret,只是因为它比修改clang代码生成器更容易。有没有更简单的方法?

在LLVM IR中按值传递结构时,必须制定自己的规则。我选择了一套最简单的规则。

假设我有一个这样的程序:

struct MyStruct {
int a;
char b, c, d, e;
};
MyStruct identityImpl(MyStruct s) {
return s;
}
MyStruct identity(MyStruct s) {
return identityImpl(s);
}

该程序的LLVM IR等效于:

void identityImpl(MyStruct *ret, const MyStruct *s) {
MyStruct localS = *s;
*ret = localS;
}
void identity(MyStruct *ret, const MyStruct *s) {
MyStruct localS = *s;
MyStruct localRet;
identityImpl(&localRet, &localS);
*ret = localRet;
}

这不是传递结构的最有效方式,因为MyStruct可以放在64位寄存器中。然而,如果优化器能够证明localS从未被写入,那么它可以删除localS并直接使用s。这两个函数都优化为对memcpy的一次调用。

这只花了半天时间。走Clang路线可能至少需要一周的时间。我仍然认为我不得不这样做很不幸,但我现在明白了问题所在。结构的传递不是由平台的C ABI指定的。

最新更新