Bill Wendling via llvm-dev
2019-Jun-27 18:07 UTC
[llvm-dev] [RFC] ASM Goto With Output Constraints
[Adding the correct cfe-dev mailing list address.] On Thu, Jun 27, 2019 at 11:06 AM Bill Wendling <isanbard at gmail.com> wrote:> Now that ASM goto support has landed, Nick Desaulniers and I wrote up a > document describing how to expand clang's implementation of ASM goto to > support output constraints. The work *should* be straight-forward, but as > always will need to be verified to work. Below is a copy of our whitepaper. > Please take a look and offer any comments you have. > > Share and enjoy! > -bw > Overview > > Support for asm goto > <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html> with output > constraints is a feature that the Linux community is interested in having. Adding > this new feature should give Clang a higher profile in the Linux community: > > > - > > It demonstrates the Clang community's commitment to supporting Linux. > - > > Developers are likely to adopt it on their own, which means they will > need to use Clang in some fashion, either as a complete replacement for or > in addition to GCC. > > Current state > > Clang's implementation of asm goto converts this code: > > int vogon(unsigned a, unsigned b) { > asm goto("poetry %0, %1" : : "r"(a), "r"(b) : : error); > return a + b; > > error: > return -1; > } > > into the following LLVM IR: > > define i32 @vogon(i32 %a, i32 %b) { > entry: > callbr void asm sideeffect "poetry $0, $1", "r,r,X" > (i32 %a, i32 %b, i8* blockaddress(@vogon, %return)) > to label %asm.fallthrough [label %return] > > asm.fallthrough: > %add = add i32 %b, %a > br label %return > > return: > %retval.0 = phi i32 [ %add, %asm.fallthrough ], [ -1, %entry ] > ret i32 %retval.0 > } > > Our proposal won't change LLVM's current behavior–i.e. a callbr without a > return value will act in the same way as the current implementation. > Proposal > > GCC restricts asm goto from having output constraints due to limitations > in its internal representation–i.e. GCC's control transfer instructions > cannot have outputs. For example: > > int vogon(int a, int b) { > asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); > return a + b; > > error: > return -1; > } > > currently fails to compile in GCC with the following error: > > <source>: In function 'vogon': > <source>:2:29: error: expected ':' before string constant > 2 | asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); > | ^~~~~ > | : > > > > ToT Clang matches GCC's behavior: > > <source>:2:30: error: 'asm goto' cannot have output constraints > asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); > > However, LLVM doesn't restrict control transfer instructions from having > outputs (e.g. the invoke instruction > <https://llvm.org/docs/LangRef.html#invoke-instruction>). We propose > changing LLVM's callbr instruction > <https://llvm.org/docs/LangRef.html#callbr-instruction> to allow return > values, similar to how LLVM's implementation of inline assembly (via the > call instruction <https://llvm.org/docs/LangRef.html#call-instruction>) > allows return values. Since there can potentially be zero to many output > constraints, callbr would now return an aggregate which contains an > element for each output constraint. These values would then be extracted > via extractvalue. With our proposal, the above C example will be > converted to LLVM IR like this: > > define i32 @vogon(i32 %a, i32 %b) { > entry: > %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" > (i8* blockaddress(@vogon, %error)) > to label %asm.fallthrough [label %error] > > > asm.fallthrough: > %asmresult.a = extractvalue { i32, i32 } %0, 0 > %asmresult.b = extractvalue { i32, i32 } %0, 1 > %result = add i32 %asmresult.a, %asmresult.b > ret i32 %result > > error: > ret i32 -1 > } > > Note that unlike the invoke instruction, callbr's return values are > assumed valid on all branches. The assumption is that the programmer > knows what their inline assembly is doing and where its output constraints > are valid. If the value isn't valid on a particular branch but is used > there anyway, then the result is a poison value. (Also, if a callbr's > return values affect a branch, it will be handled similarly to the invoke > instruction's implementation.) Here's an example of how this would work: > > int vogon(int a, int b) { > asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); > if (a == 42) > return 42 * b; > return a + b; > > error: > return b - 42; > } > > generates the following LLVM IR: > > define i32 @vogon(i32 %a, i32 %b) { > entry: > %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" > (i8* blockaddress(@vogon, %error)) > to label %asm.fallthrough [label %error] > > asm.fallthrough: > %asmresult.a = extractvalue { i32, i32 } %0, 0 > %tobool = icmp eq i32 %asmresult.a, 42 > br i1 %tobool, label %if.true, label %if.false > > if.true: > %asmresult.b = extractvalue { i32, i32 } %0, 1 > %mul = mul i32 42, %asmresult.b > ret i32 %mul > > if.false: > %asmresult.a.1 = extractvalue { i32, i32 } %0, 0 > %asmresult.b.1 = extractvalue { i32, i32 } %0, 1 > %result = add i32 %asmresult.a.1, %asmresult.b.1 > ret i32 %result > > error: > %asmresult.b.error = extractvalue { i32, i32 } %0, 1 > %error.result = sub i32 %asmresult.b.error, 42 > ret i32 %error.result > } > Implementation > > Because LLVM's invoke instruction is a terminating instruction that may > have return values, we can use it as a template for callbr's changes. The > new functionality lies mostly in modifying Clang's front-end. In > particular, we need to do the following: > > > - > > Remove all error checks restricting asm goto from returning values, and > - > > Generate the extractvalue instructions on callbr's branches. > > > LLVM's middle- and back-ends need to be audited to ensure there are no > restrictions on callbr returning a value. We expect all passes to Just > Work™ without modifications, but of course will be verified. >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190627/2c45cc04/attachment-0001.html>
Nick Desaulniers via llvm-dev
2019-Jun-27 18:10 UTC
[llvm-dev] [RFC] ASM Goto With Output Constraints
+ CBL mailing list On Thu, Jun 27, 2019 at 11:08 AM Bill Wendling <isanbard at gmail.com> wrote:> [Adding the correct cfe-dev mailing list address.] > > On Thu, Jun 27, 2019 at 11:06 AM Bill Wendling <isanbard at gmail.com> wrote: > >> Now that ASM goto support has landed, Nick Desaulniers and I wrote up a >> document describing how to expand clang's implementation of ASM goto to >> support output constraints. The work *should* be straight-forward, but >> as always will need to be verified to work. Below is a copy of our >> whitepaper. Please take a look and offer any comments you have. >> >> Share and enjoy! >> -bw >> Overview >> >> Support for asm goto >> <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html> with output >> constraints is a feature that the Linux community is interested in having. Adding >> this new feature should give Clang a higher profile in the Linux community: >> >> >> - >> >> It demonstrates the Clang community's commitment to supporting Linux. >> - >> >> Developers are likely to adopt it on their own, which means they will >> need to use Clang in some fashion, either as a complete replacement for or >> in addition to GCC. >> >> Current state >> >> Clang's implementation of asm goto converts this code: >> >> int vogon(unsigned a, unsigned b) { >> asm goto("poetry %0, %1" : : "r"(a), "r"(b) : : error); >> return a + b; >> >> error: >> return -1; >> } >> >> into the following LLVM IR: >> >> define i32 @vogon(i32 %a, i32 %b) { >> entry: >> callbr void asm sideeffect "poetry $0, $1", "r,r,X" >> (i32 %a, i32 %b, i8* blockaddress(@vogon, %return)) >> to label %asm.fallthrough [label %return] >> >> asm.fallthrough: >> %add = add i32 %b, %a >> br label %return >> >> return: >> %retval.0 = phi i32 [ %add, %asm.fallthrough ], [ -1, %entry ] >> ret i32 %retval.0 >> } >> >> Our proposal won't change LLVM's current behavior–i.e. a callbr without >> a return value will act in the same way as the current implementation. >> Proposal >> >> GCC restricts asm goto from having output constraints due to limitations >> in its internal representation–i.e. GCC's control transfer instructions >> cannot have outputs. For example: >> >> int vogon(int a, int b) { >> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >> return a + b; >> >> error: >> return -1; >> } >> >> currently fails to compile in GCC with the following error: >> >> <source>: In function 'vogon': >> <source>:2:29: error: expected ':' before string constant >> 2 | asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >> | ^~~~~ >> | : >> >> >> >> ToT Clang matches GCC's behavior: >> >> <source>:2:30: error: 'asm goto' cannot have output constraints >> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >> >> However, LLVM doesn't restrict control transfer instructions from having >> outputs (e.g. the invoke instruction >> <https://llvm.org/docs/LangRef.html#invoke-instruction>). We propose >> changing LLVM's callbr instruction >> <https://llvm.org/docs/LangRef.html#callbr-instruction> to allow return >> values, similar to how LLVM's implementation of inline assembly (via the >> call instruction <https://llvm.org/docs/LangRef.html#call-instruction>) >> allows return values. Since there can potentially be zero to many output >> constraints, callbr would now return an aggregate which contains an >> element for each output constraint. These values would then be extracted >> via extractvalue. With our proposal, the above C example will be >> converted to LLVM IR like this: >> >> define i32 @vogon(i32 %a, i32 %b) { >> entry: >> %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" >> (i8* blockaddress(@vogon, %error)) >> to label %asm.fallthrough [label %error] >> >> >> asm.fallthrough: >> %asmresult.a = extractvalue { i32, i32 } %0, 0 >> %asmresult.b = extractvalue { i32, i32 } %0, 1 >> %result = add i32 %asmresult.a, %asmresult.b >> ret i32 %result >> >> error: >> ret i32 -1 >> } >> >> Note that unlike the invoke instruction, callbr's return values are >> assumed valid on all branches. The assumption is that the programmer >> knows what their inline assembly is doing and where its output constraints >> are valid. If the value isn't valid on a particular branch but is used >> there anyway, then the result is a poison value. (Also, if a callbr's >> return values affect a branch, it will be handled similarly to the invoke >> instruction's implementation.) Here's an example of how this would work: >> >> int vogon(int a, int b) { >> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >> if (a == 42) >> return 42 * b; >> return a + b; >> >> error: >> return b - 42; >> } >> >> generates the following LLVM IR: >> >> define i32 @vogon(i32 %a, i32 %b) { >> entry: >> %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" >> (i8* blockaddress(@vogon, %error)) >> to label %asm.fallthrough [label %error] >> >> asm.fallthrough: >> %asmresult.a = extractvalue { i32, i32 } %0, 0 >> %tobool = icmp eq i32 %asmresult.a, 42 >> br i1 %tobool, label %if.true, label %if.false >> >> if.true: >> %asmresult.b = extractvalue { i32, i32 } %0, 1 >> %mul = mul i32 42, %asmresult.b >> ret i32 %mul >> >> if.false: >> %asmresult.a.1 = extractvalue { i32, i32 } %0, 0 >> %asmresult.b.1 = extractvalue { i32, i32 } %0, 1 >> %result = add i32 %asmresult.a.1, %asmresult.b.1 >> ret i32 %result >> >> error: >> %asmresult.b.error = extractvalue { i32, i32 } %0, 1 >> %error.result = sub i32 %asmresult.b.error, 42 >> ret i32 %error.result >> } >> Implementation >> >> Because LLVM's invoke instruction is a terminating instruction that may >> have return values, we can use it as a template for callbr's changes. >> The new functionality lies mostly in modifying Clang's front-end. In >> particular, we need to do the following: >> >> >> - >> >> Remove all error checks restricting asm goto from returning values, >> and >> - >> >> Generate the extractvalue instructions on callbr's branches. >> >> >> LLVM's middle- and back-ends need to be audited to ensure there are no >> restrictions on callbr returning a value. We expect all passes to Just >> Work™ without modifications, but of course will be verified. >> >-- Thanks, ~Nick Desaulniers -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190627/28aed54c/attachment-0001.html>
Craig Topper via llvm-dev
2019-Jun-27 19:31 UTC
[llvm-dev] [cfe-dev] [RFC] ASM Goto With Output Constraints
What about SelectionDAG representation? Currently we expand callbr to INLINEASM_BR and BR. Both of which are terminators. But in order to support outputs we would need to put CopyFromReg nodes between them. ~Craig On Thu, Jun 27, 2019 at 12:18 PM Nick Desaulniers via cfe-dev < cfe-dev at lists.llvm.org> wrote:> + CBL mailing list > > > On Thu, Jun 27, 2019 at 11:08 AM Bill Wendling <isanbard at gmail.com> wrote: > >> [Adding the correct cfe-dev mailing list address.] >> >> On Thu, Jun 27, 2019 at 11:06 AM Bill Wendling <isanbard at gmail.com> >> wrote: >> >>> Now that ASM goto support has landed, Nick Desaulniers and I wrote up a >>> document describing how to expand clang's implementation of ASM goto to >>> support output constraints. The work *should* be straight-forward, but >>> as always will need to be verified to work. Below is a copy of our >>> whitepaper. Please take a look and offer any comments you have. >>> >>> Share and enjoy! >>> -bw >>> Overview >>> >>> Support for asm goto >>> <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html> with output >>> constraints is a feature that the Linux community is interested in having. Adding >>> this new feature should give Clang a higher profile in the Linux community: >>> >>> >>> - >>> >>> It demonstrates the Clang community's commitment to supporting Linux. >>> - >>> >>> Developers are likely to adopt it on their own, which means they >>> will need to use Clang in some fashion, either as a complete replacement >>> for or in addition to GCC. >>> >>> Current state >>> >>> Clang's implementation of asm goto converts this code: >>> >>> int vogon(unsigned a, unsigned b) { >>> asm goto("poetry %0, %1" : : "r"(a), "r"(b) : : error); >>> return a + b; >>> >>> error: >>> return -1; >>> } >>> >>> into the following LLVM IR: >>> >>> define i32 @vogon(i32 %a, i32 %b) { >>> entry: >>> callbr void asm sideeffect "poetry $0, $1", "r,r,X" >>> (i32 %a, i32 %b, i8* blockaddress(@vogon, %return)) >>> to label %asm.fallthrough [label %return] >>> >>> asm.fallthrough: >>> %add = add i32 %b, %a >>> br label %return >>> >>> return: >>> %retval.0 = phi i32 [ %add, %asm.fallthrough ], [ -1, %entry ] >>> ret i32 %retval.0 >>> } >>> >>> Our proposal won't change LLVM's current behavior–i.e. a callbr without >>> a return value will act in the same way as the current implementation. >>> Proposal >>> >>> GCC restricts asm goto from having output constraints due to >>> limitations in its internal representation–i.e. GCC's control transfer >>> instructions cannot have outputs. For example: >>> >>> int vogon(int a, int b) { >>> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> return a + b; >>> >>> error: >>> return -1; >>> } >>> >>> currently fails to compile in GCC with the following error: >>> >>> <source>: In function 'vogon': >>> <source>:2:29: error: expected ':' before string constant >>> 2 | asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> | ^~~~~ >>> | : >>> >>> >>> >>> ToT Clang matches GCC's behavior: >>> >>> <source>:2:30: error: 'asm goto' cannot have output constraints >>> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> >>> However, LLVM doesn't restrict control transfer instructions from having >>> outputs (e.g. the invoke instruction >>> <https://llvm.org/docs/LangRef.html#invoke-instruction>). We propose >>> changing LLVM's callbr instruction >>> <https://llvm.org/docs/LangRef.html#callbr-instruction> to allow return >>> values, similar to how LLVM's implementation of inline assembly (via the >>> call instruction <https://llvm.org/docs/LangRef.html#call-instruction>) >>> allows return values. Since there can potentially be zero to many output >>> constraints, callbr would now return an aggregate which contains an >>> element for each output constraint. These values would then be extracted >>> via extractvalue. With our proposal, the above C example will be >>> converted to LLVM IR like this: >>> >>> define i32 @vogon(i32 %a, i32 %b) { >>> entry: >>> %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" >>> (i8* blockaddress(@vogon, %error)) >>> to label %asm.fallthrough [label %error] >>> >>> >>> asm.fallthrough: >>> %asmresult.a = extractvalue { i32, i32 } %0, 0 >>> %asmresult.b = extractvalue { i32, i32 } %0, 1 >>> %result = add i32 %asmresult.a, %asmresult.b >>> ret i32 %result >>> >>> error: >>> ret i32 -1 >>> } >>> >>> Note that unlike the invoke instruction, callbr's return values are >>> assumed valid on all branches. The assumption is that the programmer >>> knows what their inline assembly is doing and where its output constraints >>> are valid. If the value isn't valid on a particular branch but is used >>> there anyway, then the result is a poison value. (Also, if a callbr's >>> return values affect a branch, it will be handled similarly to the >>> invoke instruction's implementation.) Here's an example of how this >>> would work: >>> >>> int vogon(int a, int b) { >>> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> if (a == 42) >>> return 42 * b; >>> return a + b; >>> >>> error: >>> return b - 42; >>> } >>> >>> generates the following LLVM IR: >>> >>> define i32 @vogon(i32 %a, i32 %b) { >>> entry: >>> %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" >>> (i8* blockaddress(@vogon, %error)) >>> to label %asm.fallthrough [label %error] >>> >>> asm.fallthrough: >>> %asmresult.a = extractvalue { i32, i32 } %0, 0 >>> %tobool = icmp eq i32 %asmresult.a, 42 >>> br i1 %tobool, label %if.true, label %if.false >>> >>> if.true: >>> %asmresult.b = extractvalue { i32, i32 } %0, 1 >>> %mul = mul i32 42, %asmresult.b >>> ret i32 %mul >>> >>> if.false: >>> %asmresult.a.1 = extractvalue { i32, i32 } %0, 0 >>> %asmresult.b.1 = extractvalue { i32, i32 } %0, 1 >>> %result = add i32 %asmresult.a.1, %asmresult.b.1 >>> ret i32 %result >>> >>> error: >>> %asmresult.b.error = extractvalue { i32, i32 } %0, 1 >>> %error.result = sub i32 %asmresult.b.error, 42 >>> ret i32 %error.result >>> } >>> Implementation >>> >>> Because LLVM's invoke instruction is a terminating instruction that may >>> have return values, we can use it as a template for callbr's changes. >>> The new functionality lies mostly in modifying Clang's front-end. In >>> particular, we need to do the following: >>> >>> >>> - >>> >>> Remove all error checks restricting asm goto from returning values, >>> and >>> - >>> >>> Generate the extractvalue instructions on callbr's branches. >>> >>> >>> LLVM's middle- and back-ends need to be audited to ensure there are no >>> restrictions on callbr returning a value. We expect all passes to Just >>> Work™ without modifications, but of course will be verified. >>> >> > > -- > Thanks, > ~Nick Desaulniers > _______________________________________________ > cfe-dev mailing list > cfe-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190627/cb0dbfb8/attachment-0001.html>
Reid Kleckner via llvm-dev
2019-Jun-27 20:15 UTC
[llvm-dev] [cfe-dev] [RFC] ASM Goto With Output Constraints
On Thu, Jun 27, 2019 at 12:18 PM Nick Desaulniers via cfe-dev < cfe-dev at lists.llvm.org> wrote:> + CBL mailing list > On Thu, Jun 27, 2019 at 11:08 AM Bill Wendling <isanbard at gmail.com> wrote: > >> [Adding the correct cfe-dev mailing list address.] >> >> On Thu, Jun 27, 2019 at 11:06 AM Bill Wendling <isanbard at gmail.com> >> wrote: >> >>> <source>:2:30: error: 'asm goto' cannot have output constraints >>> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> >>> However, LLVM doesn't restrict control transfer instructions from having >>> outputs (e.g. the invoke instruction >>> <https://llvm.org/docs/LangRef.html#invoke-instruction>). We propose >>> changing LLVM's callbr instruction >>> <https://llvm.org/docs/LangRef.html#callbr-instruction> to allow return >>> values, similar to how LLVM's implementation of inline assembly (via the >>> call instruction <https://llvm.org/docs/LangRef.html#call-instruction>) >>> allows return values. Since there can potentially be zero to many output >>> constraints, callbr would now return an aggregate which contains an >>> element for each output constraint. These values would then be extracted >>> via extractvalue. With our proposal, the above C example will be >>> converted to LLVM IR like this: >>> >>> define i32 @vogon(i32 %a, i32 %b) { >>> entry: >>> %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" >>> (i8* blockaddress(@vogon, %error)) >>> to label %asm.fallthrough [label %error] >>> >>> >>> asm.fallthrough: >>> %asmresult.a = extractvalue { i32, i32 } %0, 0 >>> %asmresult.b = extractvalue { i32, i32 } %0, 1 >>> %result = add i32 %asmresult.a, %asmresult.b >>> ret i32 %result >>> >>> error: >>> ret i32 -1 >>> } >>> >>> Note that unlike the invoke instruction, callbr's return values are >>> assumed valid on all branches. The assumption is that the programmer >>> knows what their inline assembly is doing and where its output constraints >>> are valid. If the value isn't valid on a particular branch but is used >>> there anyway, then the result is a poison value. (Also, if a callbr's >>> return values affect a branch, it will be handled similarly to the >>> invoke instruction's implementation.) Here's an example of how this >>> would work: >>> >>Generally, I'd prefer if we didn't keep designing new features that assume the programmer knows what they're doing. Personally, I had been considering reworking LLVM's Windows EH representation to eliminate the catchswith instruction, which just exists to multiplex invoke unwind edges to multiple catch blocks. Instead, we'd use callbr, and I had been assuming it would have the normal behavior of producing the return value only along the normal path. Do you think landingpad offers alternative inspiration for how to handle this? i.e. you could have a special EHPad-like instruction (must be first non-PHI instruction) that produces a value along abnormal paths. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190627/efde325a/attachment.html>
James Y Knight via llvm-dev
2019-Jun-27 20:28 UTC
[llvm-dev] [cfe-dev] [RFC] ASM Goto With Output Constraints
I think this is fine, except that it stops at the point where things actually start to get interesting and tricky. How will you actually handle the flow of values from the callbr into the error blocks? A callbr can specify requirements on where its outputs live. So, what if two callbr, in different branches of code, specify _different_ constraints for the same output, and list the same block as a possible error successor? How can the resulting phi be codegened? It'd sure be a whole lot easier to not have the values valid on the secondary exit blocks. Can you present examples where preserving the values on the branches is be a requirement? (I feel like I've seen some before, but it'd be good to be reminded). E.g., imagine code like this: << entry: br i1 %cmp, label %true, label %false true: %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "={r8},={r9},X" (i8* blockaddress(@vogon, %error)) to label %asm.fallthrough [label %error] false: %1 = callbr { i32, i32 } asm sideeffect "poetry2 $0, $1", "={r10},={r11},X" (i8* blockaddress(@vogon, %error)) to label %asm.fallthrough [label %error] error: %vals = phi { i32, i32 } [ %0, %true ], [ %1, %false ]>>Normally, if a common register cannot be found to use across relevant block transitions, it can simply fall back on storing values on the stack. But, that's not possible with callbr, since the location is fixed by the asm, and no code can be inserted after the values are written, before the branch (as both value writes and the branch are inside the asm blob). So what can be done, in that case? One thing you might be able to do is to duplicate the error block so you have a different target for every callbr, but I'd consider that an invalid transform (because the address of the block is potentially being used as a value in the asm too). Another thing you could perhaps do is reify the source-block-number as an actual value -- storing a "1" before the callbr in true, and storing a "2" before the callbr in "false". Then conditional-branch based on that...but that's real ugly... On Thu, Jun 27, 2019 at 3:18 PM Nick Desaulniers via cfe-dev < cfe-dev at lists.llvm.org> wrote:> + CBL mailing list > > > On Thu, Jun 27, 2019 at 11:08 AM Bill Wendling <isanbard at gmail.com> wrote: > >> [Adding the correct cfe-dev mailing list address.] >> >> On Thu, Jun 27, 2019 at 11:06 AM Bill Wendling <isanbard at gmail.com> >> wrote: >> >>> Now that ASM goto support has landed, Nick Desaulniers and I wrote up a >>> document describing how to expand clang's implementation of ASM goto to >>> support output constraints. The work *should* be straight-forward, but >>> as always will need to be verified to work. Below is a copy of our >>> whitepaper. Please take a look and offer any comments you have. >>> >>> Share and enjoy! >>> -bw >>> Overview >>> >>> Support for asm goto >>> <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html> with output >>> constraints is a feature that the Linux community is interested in having. Adding >>> this new feature should give Clang a higher profile in the Linux community: >>> >>> >>> - >>> >>> It demonstrates the Clang community's commitment to supporting Linux. >>> - >>> >>> Developers are likely to adopt it on their own, which means they >>> will need to use Clang in some fashion, either as a complete replacement >>> for or in addition to GCC. >>> >>> Current state >>> >>> Clang's implementation of asm goto converts this code: >>> >>> int vogon(unsigned a, unsigned b) { >>> asm goto("poetry %0, %1" : : "r"(a), "r"(b) : : error); >>> return a + b; >>> >>> error: >>> return -1; >>> } >>> >>> into the following LLVM IR: >>> >>> define i32 @vogon(i32 %a, i32 %b) { >>> entry: >>> callbr void asm sideeffect "poetry $0, $1", "r,r,X" >>> (i32 %a, i32 %b, i8* blockaddress(@vogon, %return)) >>> to label %asm.fallthrough [label %return] >>> >>> asm.fallthrough: >>> %add = add i32 %b, %a >>> br label %return >>> >>> return: >>> %retval.0 = phi i32 [ %add, %asm.fallthrough ], [ -1, %entry ] >>> ret i32 %retval.0 >>> } >>> >>> Our proposal won't change LLVM's current behavior–i.e. a callbr without >>> a return value will act in the same way as the current implementation. >>> Proposal >>> >>> GCC restricts asm goto from having output constraints due to >>> limitations in its internal representation–i.e. GCC's control transfer >>> instructions cannot have outputs. For example: >>> >>> int vogon(int a, int b) { >>> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> return a + b; >>> >>> error: >>> return -1; >>> } >>> >>> currently fails to compile in GCC with the following error: >>> >>> <source>: In function 'vogon': >>> <source>:2:29: error: expected ':' before string constant >>> 2 | asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> | ^~~~~ >>> | : >>> >>> >>> >>> ToT Clang matches GCC's behavior: >>> >>> <source>:2:30: error: 'asm goto' cannot have output constraints >>> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> >>> However, LLVM doesn't restrict control transfer instructions from having >>> outputs (e.g. the invoke instruction >>> <https://llvm.org/docs/LangRef.html#invoke-instruction>). We propose >>> changing LLVM's callbr instruction >>> <https://llvm.org/docs/LangRef.html#callbr-instruction> to allow return >>> values, similar to how LLVM's implementation of inline assembly (via the >>> call instruction <https://llvm.org/docs/LangRef.html#call-instruction>) >>> allows return values. Since there can potentially be zero to many output >>> constraints, callbr would now return an aggregate which contains an >>> element for each output constraint. These values would then be extracted >>> via extractvalue. With our proposal, the above C example will be >>> converted to LLVM IR like this: >>> >>> define i32 @vogon(i32 %a, i32 %b) { >>> entry: >>> %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" >>> (i8* blockaddress(@vogon, %error)) >>> to label %asm.fallthrough [label %error] >>> >>> >>> asm.fallthrough: >>> %asmresult.a = extractvalue { i32, i32 } %0, 0 >>> %asmresult.b = extractvalue { i32, i32 } %0, 1 >>> %result = add i32 %asmresult.a, %asmresult.b >>> ret i32 %result >>> >>> error: >>> ret i32 -1 >>> } >>> >>> Note that unlike the invoke instruction, callbr's return values are >>> assumed valid on all branches. The assumption is that the programmer >>> knows what their inline assembly is doing and where its output constraints >>> are valid. If the value isn't valid on a particular branch but is used >>> there anyway, then the result is a poison value. (Also, if a callbr's >>> return values affect a branch, it will be handled similarly to the >>> invoke instruction's implementation.) Here's an example of how this >>> would work: >>> >>> int vogon(int a, int b) { >>> asm goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>> if (a == 42) >>> return 42 * b; >>> return a + b; >>> >>> error: >>> return b - 42; >>> } >>> >>> generates the following LLVM IR: >>> >>> define i32 @vogon(i32 %a, i32 %b) { >>> entry: >>> %0 = callbr { i32, i32 } asm sideeffect "poetry $0, $1", "=r,=r,X" >>> (i8* blockaddress(@vogon, %error)) >>> to label %asm.fallthrough [label %error] >>> >>> asm.fallthrough: >>> %asmresult.a = extractvalue { i32, i32 } %0, 0 >>> %tobool = icmp eq i32 %asmresult.a, 42 >>> br i1 %tobool, label %if.true, label %if.false >>> >>> if.true: >>> %asmresult.b = extractvalue { i32, i32 } %0, 1 >>> %mul = mul i32 42, %asmresult.b >>> ret i32 %mul >>> >>> if.false: >>> %asmresult.a.1 = extractvalue { i32, i32 } %0, 0 >>> %asmresult.b.1 = extractvalue { i32, i32 } %0, 1 >>> %result = add i32 %asmresult.a.1, %asmresult.b.1 >>> ret i32 %result >>> >>> error: >>> %asmresult.b.error = extractvalue { i32, i32 } %0, 1 >>> %error.result = sub i32 %asmresult.b.error, 42 >>> ret i32 %error.result >>> } >>> Implementation >>> >>> Because LLVM's invoke instruction is a terminating instruction that may >>> have return values, we can use it as a template for callbr's changes. >>> The new functionality lies mostly in modifying Clang's front-end. In >>> particular, we need to do the following: >>> >>> >>> - >>> >>> Remove all error checks restricting asm goto from returning values, >>> and >>> - >>> >>> Generate the extractvalue instructions on callbr's branches. >>> >>> >>> LLVM's middle- and back-ends need to be audited to ensure there are no >>> restrictions on callbr returning a value. We expect all passes to Just >>> Work™ without modifications, but of course will be verified. >>> >> > > -- > Thanks, > ~Nick Desaulniers > _______________________________________________ > cfe-dev mailing list > cfe-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190627/36bc48dc/attachment-0001.html>
Craig Topper via llvm-dev
2019-Jun-27 22:32 UTC
[llvm-dev] [cfe-dev] [RFC] ASM Goto With Output Constraints
I believe at least some portion of the INLINEASM_BR decision is discussed here https://reviews.llvm.org/D53765?id=184024#inline-508610 Anything that's on record anywhere should be in that review. I may have had some conversations with Chandler on IRC, but I'm not sure. ~Craig On Thu, Jun 27, 2019 at 2:53 PM Finkel, Hal J. <hfinkel at anl.gov> wrote:> > On 6/27/19 2:31 PM, Craig Topper via llvm-dev wrote: > > What about SelectionDAG representation? Currently we expand callbr to > INLINEASM_BR and BR. Both of which are terminators. But in order to support > outputs we would need to put CopyFromReg nodes between them. > > > Or maybe we should support having terminators that define values? People > ask about this from time to time, and that seems like the > higher-overall-value extension to make to the MI representation. > > -Hal > > > > ~Craig > > > On Thu, Jun 27, 2019 at 12:18 PM Nick Desaulniers via cfe-dev < > cfe-dev at lists.llvm.org> wrote: > >> + CBL mailing list >> >> >> On Thu, Jun 27, 2019 at 11:08 AM Bill Wendling <isanbard at gmail.com> >> wrote: >> >>> [Adding the correct cfe-dev mailing list address.] >>> >>> On Thu, Jun 27, 2019 at 11:06 AM Bill Wendling <isanbard at gmail.com> >>> wrote: >>> >>>> Now that ASM goto support has landed, Nick Desaulniers and I wrote up a >>>> document describing how to expand clang's implementation of ASM goto to >>>> support output constraints. The work *should* be straight-forward, but >>>> as always will need to be verified to work. Below is a copy of our >>>> whitepaper. Please take a look and offer any comments you have. >>>> >>>> Share and enjoy! >>>> -bw >>>> Overview >>>> >>>> Support for asm goto >>>> <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html> with output >>>> constraints is a feature that the Linux community is interested in having. Adding >>>> this new feature should give Clang a higher profile in the Linux community: >>>> >>>> >>>> - >>>> >>>> It demonstrates the Clang community's commitment to supporting >>>> Linux. >>>> - >>>> >>>> Developers are likely to adopt it on their own, which means they >>>> will need to use Clang in some fashion, either as a complete replacement >>>> for or in addition to GCC. >>>> >>>> Current state >>>> >>>> Clang's implementation of asm goto converts this code: >>>> >>>> int vogon(unsigned a, unsigned b) { asm goto("poetry %0, %1" : : "r"(a), >>>> "r"(b) : : error); return a + b; error: return -1; } >>>> >>>> into the following LLVM IR: >>>> >>>> define i32 @vogon(i32 %a, i32 %b) { entry: callbr void asm sideeffect "poetry >>>> $0, $1", "r,r,X" (i32 %a, i32 %b, i8* blockaddress(@vogon, >>>> %return)) to label %asm.fallthrough [label %return] asm >>>> .fallthrough: %add = add i32 %b, %a br label %return return: >>>> %retval.0 = phi i32 [ %add, %asm.fallthrough ], [ -1, %entry ] ret >>>> i32 %retval.0 } >>>> >>>> Our proposal won't change LLVM's current behavior–i.e. a callbr >>>> without a return value will act in the same way as the current >>>> implementation. >>>> Proposal >>>> >>>> GCC restricts asm goto from having output constraints due to >>>> limitations in its internal representation–i.e. GCC's control transfer >>>> instructions cannot have outputs. For example: >>>> >>>> int vogon(int a, int b) { asm goto("poetry %0, %1" : "=r"(a), "=r"(b) >>>> : : : error); return a + b; error: return -1; } >>>> >>>> currently fails to compile in GCC with the following error: >>>> >>>> <source>: In function 'vogon': <source>:2:29: error: expected ':' >>>> before string constant 2 | asm goto("poetry %0, %1" : "=r"(a), "=r"(b) >>>> : : : error); | ^~~~~ | >>>> : >>>> >>>> >>>> >>>> ToT Clang matches GCC's behavior: >>>> >>>> <source>:2:30: error: 'asm goto' cannot have output constraints asm >>>> goto("poetry %0, %1" : "=r"(a), "=r"(b) : : : error); >>>> >>>> However, LLVM doesn't restrict control transfer instructions from >>>> having outputs (e.g. the invoke instruction >>>> <https://llvm.org/docs/LangRef.html#invoke-instruction>). We propose >>>> changing LLVM's callbr instruction >>>> <https://llvm.org/docs/LangRef.html#callbr-instruction> to allow >>>> return values, similar to how LLVM's implementation of inline assembly (via >>>> the call instruction >>>> <https://llvm.org/docs/LangRef.html#call-instruction>) allows return >>>> values. Since there can potentially be zero to many output constraints, >>>> callbr would now return an aggregate which contains an element for >>>> each output constraint. These values would then be extracted via >>>> extractvalue. With our proposal, the above C example will be converted >>>> to LLVM IR like this: >>>> >>>> define i32 @vogon(i32 %a, i32 %b) { entry: %0 = callbr { i32, i32 } >>>> asm sideeffect "poetry $0, $1", "=r,=r,X" (i8* blockaddress( >>>> @vogon, %error)) to label %asm.fallthrough [label %error] >>>> >>>> asm.fallthrough: %asmresult.a = extractvalue { i32, i32 } %0, 0 >>>> %asmresult.b = extractvalue { i32, i32 } %0, 1 %result = add i32 >>>> %asmresult.a, %asmresult.b ret i32 %result error: ret i32 -1 } >>>> >>>> Note that unlike the invoke instruction, callbr's return values are >>>> assumed valid on all branches. The assumption is that the programmer >>>> knows what their inline assembly is doing and where its output constraints >>>> are valid. If the value isn't valid on a particular branch but is used >>>> there anyway, then the result is a poison value. (Also, if a callbr's >>>> return values affect a branch, it will be handled similarly to the >>>> invoke instruction's implementation.) Here's an example of how this >>>> would work: >>>> >>>> int vogon(int a, int b) { asm goto("poetry %0, %1" : "=r"(a), "=r"(b) >>>> : : : error); if (a == 42) return 42 * b; return a + b; error: >>>> return b - 42; } >>>> >>>> generates the following LLVM IR: >>>> >>>> define i32 @vogon(i32 %a, i32 %b) { entry: %0 = callbr { i32, i32 } >>>> asm sideeffect "poetry $0, $1", "=r,=r,X" (i8* blockaddress( >>>> @vogon, %error)) to label %asm.fallthrough [label %error] asm >>>> .fallthrough: %asmresult.a = extractvalue { i32, i32 } %0, 0 >>>> %tobool = icmp eq i32 %asmresult.a, 42 br i1 %tobool, label %if.true, >>>> label %if.false if.true: %asmresult.b = extractvalue { i32, i32 } %0, >>>> 1 %mul = mul i32 42, %asmresult.b ret i32 %mul if.false: >>>> %asmresult.a.1 = extractvalue { i32, i32 } %0, 0 %asmresult.b.1 >>>> extractvalue { i32, i32 } %0, 1 %result = add i32 %asmresult.a.1, >>>> %asmresult.b.1 ret i32 %result error: %asmresult.b.error >>>> extractvalue { i32, i32 } %0, 1 %error.result = sub i32 >>>> %asmresult.b.error, 42 ret i32 %error.result } >>>> Implementation >>>> >>>> Because LLVM's invoke instruction is a terminating instruction that >>>> may have return values, we can use it as a template for callbr's >>>> changes. The new functionality lies mostly in modifying Clang's front-end. >>>> In particular, we need to do the following: >>>> >>>> >>>> - >>>> >>>> Remove all error checks restricting asm goto from returning values, >>>> and >>>> - >>>> >>>> Generate the extractvalue instructions on callbr's branches. >>>> >>>> >>>> LLVM's middle- and back-ends need to be audited to ensure there are no >>>> restrictions on callbr returning a value. We expect all passes to Just >>>> Work™ without modifications, but of course will be verified. >>>> >>> >> >> -- >> Thanks, >> ~Nick Desaulniers >> _______________________________________________ >> cfe-dev mailing list >> cfe-dev at lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev >> > > _______________________________________________ > LLVM Developers mailing listllvm-dev at lists.llvm.orghttps://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > -- > Hal Finkel > Lead, Compiler Technology and Programming Languages > Leadership Computing Facility > Argonne National Laboratory > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190627/771ee58c/attachment-0001.html>