简体   繁体   English

阻止clang扩展聚合类型的参数?

[英]Prevent clang from expanding arguments that are aggregate types?

I'm using clang to spit out optimized LLVM IR for some C code and I've hit a snag. 我正在使用clang为一些C代码吐出优化的LLVM IR,我遇到了麻烦。 I'd assumed that, if I only passed functions to clang one at a time (with the necessary dependencies declared), the function signatures of the resulting LLVM routines would be consistent with the functions I'd passed in (ie. same number of arguments with the same types). 我假设,如果我只传递函数一次铿锵一声(声明必要的依赖项),结果LLVM例程的函数签名将与我传入的函数一致(即相同的数量)具有相同类型的参数)。 This works for the most part, except in the case of aggregate types. 这在大多数情况下都有效,除了聚合类型的情况。 For example: 例如:

The following C code 以下C代码

struct A {
    double x;
    int y;
};

int f(struct A a) {
    return a.y;
}

Results in the following LLVM 结果在以下LLVM中

; Function Attrs: nounwind readnone uwtable
define i32 @f(double %a.coerce0, i32 %a.coerce1) #0 {
entry:
  ret i32 %a.coerce1
}

The struct has been expanded into consecutive arguments so that the function now appears to accept two arguments instead of one. 结构已经扩展为连续的参数,因此函数现在看起来接受两个参数而不是一个。 Is there any way of preventing this type of expansion? 有没有办法防止这种扩张? Even if it's some way of forward declaring the struct so that clang won't know about its constituent fields in order to expand it? 即使它是某种向前声明结构的方式,以便clang不会知道它的组成字段以扩展它?

Thanks for the help! 谢谢您的帮助!

This behaviour is specified by the AMD64 ABI (application binary interface for x86 64-bit architecture). 此行为由AMD64 ABI (x86 64位体系结构的应用程序二进制接口)指定。 It's specified in the ABI so that functions compiled by different compilers can interoperate. 它在ABI中指定,以便不同编译器编译的函数可以互操作。 For the same reason, it cannot be changed without violating the ABI, which would mean that all clients of the function would need to know how it was to be called. 出于同样的原因,它不能在不违反ABI的情况下进行更改,这意味着该函数的所有客户端都需要知道如何调用它。

The ABI requires that aggregate objects be split in this fashion if: ABI要求在以下情况下以这种方式拆分聚合对象:

  • The aggregate object is not more than 16 bytes in size, and 聚合对象的大小不超过16个字节

  • In the case of C++, the aggregate object is "POD" (Plain Old Data). 在C ++的情况下,聚合对象是“POD”(普通旧数据)。

Otherwise, the argument is passed by address (although a copy still needs to be made). 否则,参数将通过地址传递(尽管仍需要复制)。

So you can defeat the deaggregation of aggregate types by making the type larger, but that must be visible to every translation unit which uses the type. 因此,您可以通过使类型更大来抵消聚合类型的分解,但对于使用该类型的每个翻译单元必须是可见的。

You could also pass things around by void * and cast the memory to the struct you want, but a better question is why you're trying to avoid having the front end do some of the type based lowering it's required to do (The ABI answer above). 您也可以通过void *传递内容并将内存转换为您想要的结构,但更好的问题是为什么您要避免让前端执行一些基于类型的降低它需要执行的操作(ABI答案)以上)。 FWIW we could do this in the back end as well, but it requires front end type information to do the lowering correctly and is a bit of a large change for llvm and clang. FWIW我们也可以在后端执行此操作,但它需要前端类型信息才能正确执行降低,并且对于llvm和clang来说是一个很大的变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM