[LLVMdev] naked assembler / function written entirely in asm

Tomas Lindquist Olsen tomas.l.olsen at gmail.com
Fri Jan 9 14:47:36 PST 2009


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>


More information about the llvm-dev mailing list