Trouble with inline asm

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;
}

if the *** line is commented I get this LL (unrelevant stuff removed):

; ModuleID = 'tangotests.asm1'
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:8"
target triple = "i686-unknown-linux-gnu"

@.stringliteral = internal constant [4 x i8] c"%d\0A\00"
; <[4 x i8]*> [#uses=1]

declare i32 @printf(i8*, ...)

define fastcc i32 @_Dmain() {
entry_tangotests.asm1.main:
        %i = alloca i32 ; <i32*> [#uses=4]
        store i32 12, i32* %i
        %tmp = load i32* %i ; <i32> [#uses=1]
        %tmp1 = call i32 (i8*, ...)* @printf( i8* getelementptr ([4 x
i8]* @.stringliteral, i32 0, i32 0), i32 %tmp ) ; <i32>
[#uses=0]
        %tmp2 = load i32* %i ; <i32> [#uses=1]
        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 )
        %tmp3 = load i32* %i ; <i32> [#uses=1]
        %tmp4 = call i32 (i8*, ...)* @printf( i8* getelementptr ([4 x
i8]* @.stringliteral, i32 0, i32 0), i32 %tmp3 ) ; <i32>
[#uses=0]
        ret i32 0
}

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.

Thanx, Tomas Lindquist Olsen

[1] : ldc - D Programming Language - Trac

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.

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.

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

-Eli

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 :wink: 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@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 :slight_smile:

Incidentally, llvm-gcc has partial support for this with the -fasm-blocks command line option. This code is accepted by apple gcc:

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;
}

But it looks like it is currently rejected by llvm-gcc (invalid or unsupported asm). This is a bug that we will fix in time. I think that the GCC front-end makes the same mistake as the D front-end, where it lowers each statement into a separate inline asm node. Here's an example that does work with llvm-gcc, though it produces ugly code like Apple GCC (pinning 'i' to the stack):

int printf(char*,...);
int main()
{
    int i = 12;
    printf("%d\n", i);
    asm
    {
        shl i, 1
    }
    printf("%d\n", i);
    return 0;
}

-Chris