<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">On Dec 9, 2020, at 8:21 AM, Nicolai Hähnle via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a>> wrote:<div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="">We may eventually find some use for this as well, though it's speculative.<br class=""></div><div class=""><br class=""></div><div class="">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?</div></div></div></blockquote><div><br class=""></div><div>I would love to see this conceptually.  “First class aggregates” in LLVM are a historical mistake in my opinion.</div><div><br class=""></div><div>Such a transition is going to be a beast though.</div><div><br class=""></div><div>-Chris</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">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.<br class=""></div><div class=""><br class=""></div><div class="">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. <br class=""></div><div class=""><br class=""></div><div class="">Cheers,</div><div class="">Nicolai<br class=""></div><br class=""><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Dec 9, 2020 at 2:31 PM Tim Northover via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">One line proposal: I want to be able to write<br class="">
<br class="">
    declare { i8 signext, i16 zeroext } @foo()<br class="">
<br class="">
I think it's probably justifiable purely on symmetry grounds, a returned struct<br class="">
is really just a glorified parameter list to fit in with LLVM's requirement that<br class="">
a call produce a single Value, and why shouldn't you have as much control over<br class="">
how that parameter passing happens as you do on the call itself?<br class="">
<br class="">
But I do have a real motivating bugbear. Swifterror and the unfortunate fact<br class="">
that I need a second attribute like it.<br class="">
<br class="">
The swifterror attribute was implemented to support a special kind of function<br class="">
parameter that gets passed and then returned in a specific register,<br class="">
but functions<br class="">
can change.<br class="">
<br class="">
The "specific register" requirement is slightly odd, but shared by "swiftself"<br class="">
parameters and not a big problem to represent.<br class="">
<br class="">
But because we can't currently describe that final return (of a possibly<br class="">
different value), we perform an elaborate trick on the IR. Values are given a<br class="">
pseudo-memory location (created with a special alloca), and syntactic load/store<br class="">
operations to this get converted to normal vreg dataflow by a special<br class="">
SwiftErrorValueTracking class that essentially implements a subset of mem2reg<br class="">
behaviour during CodeGen. The final value is then magically returned in x21 (for<br class="">
AArch64).<br class="">
<br class="">
So in current IR you will see functions like this (with AArch64 real behaviour<br class="">
in comments):<br class="">
<br class="">
    define i32 @foo(i8** swifterror %loc) {<br class="">
      %errval = load i8*, i8** %loc     ; mov xErrVal, x21<br class="">
      ; Use current errval.<br class="">
      store i8* %newerr, i8** %loc      ; mov x21, xNewErr<br class="">
      [...]<br class="">
      ret i32 42 ; x0=42, x21=either incoming error, or new one if<br class="">
stored at some point.<br class="">
    }<br class="">
<br class="">
I'd like to replace them with what's really happening:<br class="">
<br class="">
    define { i32, i8* swifterror } @foo(i8* swifterror %errval) {<br class="">
      [...]<br class="">
      %ret.0 = insertvalue { i32, i8* } undef, i32 42, 0<br class="">
      %ret = insertvalue { i32, i8* } %ret.0, i8* %newerr, 1<br class="">
      ret { i32, i8* } %ret<br class="">
    }<br class="">
<br class="">
Front-ends can of course use a normal alloca to avoid explicitly value-tracking<br class="">
%newerr themselves and the real mem2reg will clean up the details.<br class="">
<br class="">
What about sret?<br class="">
----------------<br class="">
<br class="">
I think in this new world we'd have to relax the restriction that sret functions<br class="">
must otherwise return void, certainly to support the swifterror use-case. I<br class="">
don't think this is a huge problem though.<br class="">
<br class="">
Which attributes would be allowed?<br class="">
----------------------------------<br class="">
<br class="">
I'd propose starting small. Perhaps just allow signext and zeroext and<br class="">
convert swifterror in a separate patch. If people find uses for other attributes<br class="">
they can be added later.<br class="">
<br class="">
How do these combine with top-level return attributes?<br class="">
------------------------------------------------------<br class="">
<br class="">
Struct return types don't currently allow attributes; you can't write<br class="">
<br class="">
    define { i32, i32 } signext @foo() {<br class="">
<br class="">
I think it's fine to keep that restriction and only allow attributes on<br class="">
first-level inner types of structs.<br class="">
<br class="">
We'd be essentially creating a dual to the function's parameter list, but it<br class="">
has to be written as a struct because call instructions can only produce<br class="">
a single Value in LLVM (at one point I toyed with a new syntax like C++'s "auto<br class="">
foo() -> (i32, i32)" but discarded that idea for this reason, as well as the<br class="">
scale of that change).<br class="">
<br class="">
Where's the code?<br class="">
-----------------<br class="">
<br class="">
I haven't implemented it yet because it's quite a big change and I wanted to<br class="">
make sure there weren't too many objections, and that I hadn't missed<br class="">
an unmovable blocker.<br class="">
<br class="">
Cheers.<br class="">
<br class="">
Tim.<br class="">
_______________________________________________<br class="">
LLVM Developers mailing list<br class="">
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank" class="">llvm-dev@lists.llvm.org</a><br class="">
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank" class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br class="">
</blockquote></div><br clear="all" class=""><br class="">-- <br class=""><div dir="ltr" class="gmail_signature">Lerne, wie die Welt wirklich ist,<br class="">aber vergiss niemals, wie sie sein sollte.</div></div>
_______________________________________________<br class="">LLVM Developers mailing list<br class=""><a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a><br class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev<br class=""></div></blockquote></div><br class=""></body></html>