I'm not sure exactly what is causing the problem (swift, the clang importer or the llvm back end) in my case, but somehow a call to a C function that returns a struct is not lowering correctly.
In my imported C header, I have these declarations...
typedef struct {
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
} longRand4Type;
longRand4Type _longRandom4();
When that is imported into Swift, the resulting declarations in IR look like this...
%struct.longRand4Type = type { i8, i8, i8, i8 }
; Function Attrs: optsize
declare void @_longRandom4(%struct.longRand4Type* sret align 1) local_unnamed_addr #1
...a typical call site in my code...
let r = _longRandom4()
...lowers to something like this...
call void @_longRandom4(%struct.longRand4Type* noalias nocapture nonnull sret %4)
...where %4
contains a pointer to an alloca'd 4 byte space on the stack where the result should go.
The call site is lowered into final machine code as something like...
9c2: c4 01 movw r24, r8
9c4: 0e 94 2a 05 call 0xa54 ; 0xa54 <_longRandom4>
...where in this case, the pointer to the stack is in the r8/r9 register pair. And in the avr-gcc ABI, r45/r25 is the first parameter passed to a function.
So something in the clang importer/swift/IL etc. is producing code that passes a pointer to _longRandom4 rather than expecting _longRandom4 to return a 32 bit value in r22/r23/r24/r25 (which is what it actually does).
I guess what I'm trying to understand is what is at fault? Why does the clang importer produce IR that seems to return void and take a pointer parameter? Is that the llvm standard somehow? Or is that a bug in my version of the clang importer?
And if it's the expected behaviour, does this mean that there's a bug in the AVR back end, where it should "know" how to lower that IL... perhaps it should always be adding a shim of some sort, like copying the value of the pointer somewhere safe, then after the call to _longRandom4, copying the values of r22-r25 into the indirect referenced memory address?
As ever, if there's an AVR back end bug, I want to alert the maintainer, and also try to work out a pragmatic way forward, like making sure I never import a C function that returns a struct until it's fixed?