Tomas Lindquist Olsen
2009-Jan-09 22:47 UTC
[LLVMdev] naked assembler / function written entirely in asm
Hi everybody. I'm having (yet) another look at trying to get naked functions from D (1) working in our LLVM D Compiler - LDC (2). I have this test case: /// D CODE /// extern(C) int printf(char*, ...); ulong retval() { asm { naked; mov EAX, 0xff; mov EDX, 0xaa; ret; } } ulong retval2() { return (cast(ulong)0xaa << 32) | 0xff; } void main() { printf("%llu\n%llu\n", retval(), retval2()); } /// /// I've tried out a few things. This currently compiles to: /// /// 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 = "i686-pc-linux-gnu" @.str1 = internal constant [11 x i8] c"%llu\0A%llu\0A\00" ; <[11 x i8]*> [#uses=1] declare i32 @printf(i8*, ...) define x86_stdcallcc i64 @_D3bar6retvalFZm() noinline { entry: call void asm sideeffect "movl $0, %eax ; movl $1, %edx ; ret ", "i,i,~{eax},~{edx}"(i32 255, i32 170) unreachable } define x86_stdcallcc i64 @_D3bar7retval2FZm() { entry: ret i64 730144440575 } define x86_stdcallcc i32 @_Dmain({ i32, { i32, i8* }* } %unnamed) { entry: %tmp = call x86_stdcallcc i64 @_D3bar6retvalFZm() ; <i64> [#uses=1] %tmp1 = call x86_stdcallcc i64 @_D3bar7retval2FZm() ; <i64> [#uses=1] %tmp2 = call i32 (i8*, ...)* @printf(i8* getelementptr ([11 x i8]* @.str1, i32 0, i32 0), i64 %tmp, i64 %tmp1) ; <i32> [#uses=0] ret i32 0 } /// /// When this is linked as an application, without being optimized, it works as expected. But when optimized, _Dmain is reduced to: /// /// define x86_stdcallcc i32 @_Dmain({ i32, { i32, i8* }* } %unnamed) noreturn nounwind { entry: %tmp = call x86_stdcallcc i64 @_D3bar6retvalFZm() ; <i64> [#uses=0] unreachable } /// /// If the first impl is changed to: /// /// define x86_stdcallcc i64 @_D3bar6retvalFZm() noinline { entry: call void asm sideeffect "movl $0, %eax ; movl $1, %edx ; ret ", "i,i,~{eax},~{edx}"(i32 255, i32 170) ret i64 undef ; } /// /// It still works when not optimized. However, when optimized, then _Dmain becomes: /// /// define x86_stdcallcc i32 @_Dmain({ i32, { i32, i8* }* } %unnamed) { entry: %tmp = call x86_stdcallcc i64 @_D3bar6retvalFZm() ; <i64> [#uses=0] %tmp1 = call x86_stdcallcc i64 @_D3bar7retval2FZm() ; <i64> [#uses=0] %tmp2 = call i32 (i8*, ...)* @printf(i8* getelementptr ([11 x i8]* @.str1, i32 0, i32 0), i64 undef, i64 730144440575) ; <i32> [#uses=0] ret i32 0 } /// /// which (as expected) prints a bogus value. I realize I'm entering some undefined/invalid territory here, but I'd really like to get some ideas for what I could do to make this D code work. Ideally I would like a naked attribute for a function which would mean that the entire function is composed of a single asm block. Module level assembler could probably be used for this, but it would be nice if we could get away with using a single asm translator in the compiler. Thanx in advance, - Tomas Lindquist Olsen ---------------------- (1): http://digitalmars.com/d/1.0/index.html (2): http://dsource.org/projects/ldc -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20090109/e4d76103/attachment.html>
Chris Lattner
2009-Jan-11 03:54 UTC
[LLVMdev] naked assembler / function written entirely in asm
On Jan 9, 2009, at 2:47 PM, Tomas Lindquist Olsen wrote:> Hi everybody. > > I'm having (yet) another look at trying to get naked functions from > D (1) working in our LLVM D Compiler - LDC (2).> Module level assembler could probably be used for this, but it would > be nice if we could get away > with using a single asm translator in the compiler.I really do think that module-level asm is the right solution here. Unfortunately, the semantics of naked functions are very touchy, and you don't want (for example) the inliner to try inlining these things. -Chris