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