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] : http://www.dsource.org/projects/llvmdc
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.> 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
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 :)