[llvm-dev] On passing structures in registers

David Chisnall via llvm-dev llvm-dev at lists.llvm.org
Fri Sep 10 06:16:43 PDT 2021


On 10/09/2021 14:03, james faure via llvm-dev wrote:
> There are several ways to pass structures in and out of functions, and 
> the fastest will presumably usually be in registers.
> 
> Return:
> System V lets us use 2 64-bit registers for structure returns

SysV does not.  A psABI supplement to SysV does.  I guess that you're 
talking about the x86-64 psABI here?

, where
> figuring this out seems to be the frontend's problem; If the packed 
> struct is <= 128 bits, pass it by value as a llvm aggregate (and use 
> extractvalue and insertvalue to manipulate it) otherwise write to a 
> pointer with "sret" attribute and return void. It seems that once I 
> commit to the sret style, llvm can no longer return the struct in 
> registers, but I am also suspicious of always returning structs by 
> value, and even recall reading somewhere that llvm is not good at 
> handling large aggregates (maybe that applies mainly to loads and stores).
> 
> Struct arguments:
> Here too we have a choice between passing a llvm aggregate or passing 
> down a pointer argument with "byval" attribute. As before it is unclear 
> which should be preferred.

It is unclear.  This is, unfortunately, a known problem with LLVM. 
There is an implicit contract between the back end and front end on how 
ABI-specific information is lowered and this often impacts mid-level 
optimisers.  For example, if you want to return a structure of two 
32-bit values (for example, a pair of pointers) in registers on x86 (as 
the BSD / macOS 32-bit ABIs do, but the Linux 32-bit ABI does not, 
though I think Linux does this for _Complex(int)) then this contract 
says that you should return them in an i64.  This then causes problems 
for alias analysis because the ptrtoint / inttoptr pair are treated as 
escaping.

The best advice (which, I admit, is very bad) is to copy whatever clang 
does.

Various people have discussed adding an ABI library or a better way of 
expressing ABI constraints (e.g. function / parameter attributes 
requiring specific registers / stack locations) into the IR.  If you 
wanted to work on this, I personally would be incredibly happy, but it's 
a fairly large amount of work.

> I'm also curious about how best to represent bitvectors, and have 
> noticed clang sometimes casting structures to arrays; I currently use 
> raw arrays of %i1 and extract|insert value.

In general, avoid using anything other than i{N*8} as an in-memory 
representation.  i1 is typically legalised to i8 at some point in the 
back-end lowering, so if you want to guarantee that something is a 
single bit in memory then you should use an array of i8s and masking 
operations.  The back end will infer bitfield insert / extract 
instructions where available.

> My final concern is that the convention needs to be predictable, both 
> for ABI compatibility reasons and to inform appropriate Bitcasting of 
> function pointers. I would also like to understand what exactly informs 
> the threshold for switching strategy.

I completely agree that the convention should be predictable. 
Unfortunately, there is currently little consistency in LLVM over how 
these implicit contracts between back and front-end are expressed.

The root cause of a lot of these problems is that LLVM occasionally 
pretends that the contents of memory is typed, but does not do so very 
well.  The opaque pointer work is slowly fixing the most obvious 
problems here.

David


More information about the llvm-dev mailing list