[cfe-dev] [RFC] ASM Goto With Output Constraints

Craig Topper via cfe-dev cfe-dev at lists.llvm.org
Thu Jun 27 12:31:57 PDT 2019


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/cfe-dev/attachments/20190627/cb0dbfb8/attachment.html>


More information about the cfe-dev mailing list