简体   繁体   中英

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. 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). This works for the most part, except in the case of aggregate types. For example:

The following C code

struct A {
    double x;
    int y;
};

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

Results in the following 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?

Thanks for the help!

This behaviour is specified by the AMD64 ABI (application binary interface for x86 64-bit architecture). It's specified in the ABI so that functions compiled by different compilers can interoperate. 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.

The ABI requires that aggregate objects be split in this fashion if:

  • The aggregate object is not more than 16 bytes in size, and

  • In the case of C++, the aggregate object is "POD" (Plain Old Data).

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). 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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