[LLVMdev] Trouble with inline asm

Tomas Lindquist Olsen tomas.l.olsen at gmail.com
Sat Jun 7 11:16:49 PDT 2008


On Fri, Jun 6, 2008 at 9:29 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
> On Fri, Jun 6, 2008 at 6:32 AM, Tomas Lindquist Olsen
> <tomas.l.olsen at gmail.com> wrote:
>> Hi all,
>>
>> I'm having some trouble with inline asm expressions, more specifically
>> how to create the right FunctionType for a given constraint set.
>> So far it has worked well for inputs, but not for outputs. The inline
>> asm support in this language (which is D, LLVMDC[1]) is through asm
>> *statements*.
>> I never have inline asm *expressions*, and outputs are always via memory.
>>
>> I D my test looks like this:
>>
>> extern(C) int printf(char*,...);
>> int main()
>> {
>>    int i = 12;
>>    printf("%d\n", i);
>>    asm
>>    {
>>        mov EAX, i;
>>        add EAX, EAX;
>>        mul EAX, 2;
>>        mov i, EAX; // ***
>>    }
>>    printf("%d\n", i);
>>    return 0;
>> }
>
> Equivalent C code using gcc inline asm:
> int main() {
> int i = 12;
> printf("%d\n", i);
> asm("movl %1, %%eax;add %%eax,%%eax;imull $2, %%eax; movl %%eax, %0":
> "=g"(i):
> "g"(i):
> "%eax");
> printf("%d\n", i);
> return 0;
> }
>
> And the LL llvm-gcc generates:
> target datalayout =
> "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
> target triple = "i386-pc-linux-gnu"
> @.str = internal constant [4 x i8] c"%d\0A\00"          ; <[4 x i8]*> [#uses=1]
>
> define i32 @main() nounwind  {
> entry:
>        %i = alloca i32         ; <i32*> [#uses=4]
>        store i32 12, i32* %i, align 4
>        %tmp2 = call i32 (i8*, ...)* @printf( i8* getelementptr ([4 x i8]*
> @.str, i32 0, i32 0), i32 12 ) nounwind                 ; <i32> [#uses=0]
>        %tmp3 = load i32* %i, align 4           ; <i32> [#uses=1]
>        call void asm "movl $1, %eax;add %eax,%eax;imull $$2, %eax; movl
> %eax, $0", "=*imr,imr,~{dirflag},~{fpsr},~{flags},~{ax}"( i32* %i, i32
> %tmp3 ) nounwind
>        %tmp4 = load i32* %i, align 4           ; <i32> [#uses=1]
>        %tmp5 = call i32 (i8*, ...)* @printf( i8* getelementptr ([4 x i8]*
> @.str, i32 0, i32 0), i32 %tmp4 ) nounwind              ; <i32> [#uses=0]
>        ret i32 0
> }
>
> declare i32 @printf(i8*, ...) nounwind
>
>>        call void asm sideeffect "movl $0, %eax", "m,~{eax}"( i32 %tmp2 )
>>        call void asm sideeffect "addl %eax, %eax", "~{eax},~{eax}"( )
>>        call void asm sideeffect "mull $0", "i,~{eax},~{edx},~{eax}"( i32 2 )
>
> You can't safely split the lines of an asm like that; that's just
> inviting trouble because the compiler can't know that eax shouldn't be
> modified between the lines of the asm.  You have to map from one asm
> block to one asm call.

The reason we're doing it like this is that the frontend we use emit
the block as individual statements, one per instruction... it's weird!
So far it seems to be working as long as there is nothing between the
asm calls, but we will fix this eventually!

>
>> Now... No matter what I try I can't figure out what the function
>> signature should be for the *** line. I always get the assertion:
>>        InlineAsm.cpp:43: llvm::InlineAsm::InlineAsm(const
>> llvm::FunctionType*, const std::string&, const std::string&, bool):
>> Assertion `Verify(Ty, constraints) && "Function type not legal for
>> constraints!"' failed.
>>
>> The inline expr I try to create is like:
>>
>>        call void asm sideeffect "movl %eax, $0", "=m" (i32* var)
>>
>> Any clues would be much appreciated! I'd like to say that I'm very new
>> with this format of assembler, constraints etc.
>
> It looks like you're missing the "*"?  The llvm syntax for this stuff
> isn't very well documented; I'd suggest looking at llvm-gcc output if
> you want to know how to write something in particular.

Yup, it was indeed the "*" that was missing, we've got things to work
kinda well now, thanx.

>
> Good luck doing this; I imagine this is going to be tricky to
> implement, especially converting from Intel to AT&T syntax.

Thanx, we'll need it ;) Fortunately much of the code is already in
place (taken from the GDC D compiler), so it "only" had to be adapted
from GCC to LLVM.

>
> -Eli
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>

All in all after getting the * modifier in place, LLVM inline asm has
been fairly nice to work with so far :)



More information about the llvm-dev mailing list