One line proposal: I want to be able to write
declare { i8 signext, i16 zeroext } @foo()
I think it's probably justifiable purely on symmetry grounds, a returned struct
is really just a glorified parameter list to fit in with LLVM's requirement that
a call produce a single Value, and why shouldn't you have as much control over
how that parameter passing happens as you do on the call itself?
But I do have a real motivating bugbear. Swifterror and the unfortunate fact
that I need a second attribute like it.
The swifterror attribute was implemented to support a special kind of function
parameter that gets passed and then returned in a specific register,
but functions
can change.
The "specific register" requirement is slightly odd, but shared by "swiftself"
parameters and not a big problem to represent.
But because we can't currently describe that final return (of a possibly
different value), we perform an elaborate trick on the IR. Values are given a
pseudo-memory location (created with a special alloca), and syntactic load/store
operations to this get converted to normal vreg dataflow by a special
SwiftErrorValueTracking class that essentially implements a subset of mem2reg
behaviour during CodeGen. The final value is then magically returned in x21 (for
AArch64).
So in current IR you will see functions like this (with AArch64 real behaviour
in comments):
define i32 @foo(i8** swifterror %loc) {
%errval = load i8*, i8** %loc ; mov xErrVal, x21
; Use current errval.
store i8* %newerr, i8** %loc ; mov x21, xNewErr
[...]
ret i32 42 ; x0=42, x21=either incoming error, or new one if
stored at some point.
}
I'd like to replace them with what's really happening:
define { i32, i8* swifterror } @foo(i8* swifterror %errval) {
[...]
%ret.0 = insertvalue { i32, i8* } undef, i32 42, 0
%ret = insertvalue { i32, i8* } %ret.0, i8* %newerr, 1
ret { i32, i8* } %ret
}
Front-ends can of course use a normal alloca to avoid explicitly value-tracking
%newerr themselves and the real mem2reg will clean up the details.
What about sret?