[llvm-dev] [RFC] Granular Return Attributes

Chris Lattner via llvm-dev llvm-dev at lists.llvm.org
Wed Dec 9 15:25:06 PST 2020


On Dec 9, 2020, at 8:21 AM, Nicolai Hähnle via llvm-dev <llvm-dev at lists.llvm.org> wrote:
> We may eventually find some use for this as well, though it's speculative.
> 
> This may be a good time to raise the question: How do people feel about changing LLVM IR to allow multiple values defined by a single instruction?

I would love to see this conceptually.  “First class aggregates” in LLVM are a historical mistake in my opinion.

Such a transition is going to be a beast though.

-Chris

> 
> That's a pretty significant change, but I think there are very good reasons for wanting to do this. I know we'd appreciate not having the IR obfuscated by `extractvalue`, for example. Smoothing the road of LLVM IR / MLIR integration is another one.
> 
> I understand you may not want to get your particular problem blocked by such a major change. Either way, it doesn't feel like the changes would be in conflict with each other anyway. 
> 
> Cheers,
> Nicolai
> 
> On Wed, Dec 9, 2020 at 2:31 PM Tim Northover via llvm-dev <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
> 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?
> ----------------
> 
> I think in this new world we'd have to relax the restriction that sret functions
> must otherwise return void, certainly to support the swifterror use-case. I
> don't think this is a huge problem though.
> 
> Which attributes would be allowed?
> ----------------------------------
> 
> I'd propose starting small. Perhaps just allow signext and zeroext and
> convert swifterror in a separate patch. If people find uses for other attributes
> they can be added later.
> 
> How do these combine with top-level return attributes?
> ------------------------------------------------------
> 
> Struct return types don't currently allow attributes; you can't write
> 
>     define { i32, i32 } signext @foo() {
> 
> I think it's fine to keep that restriction and only allow attributes on
> first-level inner types of structs.
> 
> We'd be essentially creating a dual to the function's parameter list, but it
> has to be written as a struct because call instructions can only produce
> a single Value in LLVM (at one point I toyed with a new syntax like C++'s "auto
> foo() -> (i32, i32)" but discarded that idea for this reason, as well as the
> scale of that change).
> 
> Where's the code?
> -----------------
> 
> I haven't implemented it yet because it's quite a big change and I wanted to
> make sure there weren't too many objections, and that I hadn't missed
> an unmovable blocker.
> 
> Cheers.
> 
> Tim.
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev <https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev>
> 
> 
> -- 
> Lerne, wie die Welt wirklich ist,
> aber vergiss niemals, wie sie sein sollte.
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20201209/b623e5fc/attachment.html>


More information about the llvm-dev mailing list