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

Nick Desaulniers via cfe-dev cfe-dev at lists.llvm.org
Thu Jun 27 11:10:32 PDT 2019


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


More information about the cfe-dev mailing list