Inline assembler in D and LDC, round 2

Tomas Lindquist Olsen tomas.l.olsen at gmail.com
Wed Feb 4 12:07:02 PST 2009


Hello everybody.

Here comes the second round of inline asm discussion related to LDC,
the LLVM D Compiler.
Last time was about naked inline asm and the problems it poses for a
backend like LLVM.
Since revision 920 in our mercurial tree, naked inline asm support is
good enough that Don's Bigint code from Tango now works. This is a
great step forward...

I implemented it by using a feature in LLVM that allows you to insert
raw assembly at the codeunit level, and modified the asm processor to
support generating that as well. It wasn't that big a job really,
isn't completely finished yet, and still needs a lot of testing of
course ;)

Now Christian Kamm also finished the last ABI / calling-convention
bits we were missing on x86-32 Linux. This naturally lead us to try
out defining the "controversial" D_InlineAsm_X86 version identifier...

Now in Tango there's a bunch of code, like the following (copied from
tango.math.IEEE.d)

real ldexp(real n, int exp) /* intrinsic */
{
    version(Really_D_InlineAsm_X86)
    {
        asm {
            fild exp;
            fld n;
            fscale;
            fstp ST(1), ST(0);
        }
    }
    else
    {
        return tango.stdc.math.ldexpl(n, exp);
    }
}

This code assumes that the value of ST(0) is preserved after the asm
block ends and that the compiler simply inserts a return instruction
as appropriate.
This doesn't work with LLVM. For the function to be valid in codegen,
we must insert a return instruction in the LLVM IR code after the
block, and the only choices we have for the value to return is an
undefined value. This kind of code usually works when the program
isn't optimized, however, if optimization is enabled, a caller of
ldexp will most likely notice that the return value is undefined or a
constant, and so has a lot of freedom to do what it wants. Breaking
the way the return value is received in the process.

This is almost exactly the same problem I had with naked inline asm,
and the only fix is to somehow generate an inline asm expression
(that's what llvm has, not statements like D), that produces the right
return value. Something a bit like:

return asm { ... }

Since D has no way to express this directly, it means we would have to
analyze the inline asm and somehow capture the right registers etc.
This is not something I want to implement right now, if ever...

The LLVM people are not interested in adding some kind of feature to
allow this, since the inline asm expressions already suffice for
normal GCC (which has inline asm expressions) C/C++ code.

Now the real question is, does this code even have well defined
semantics in terms of the D spec? and if not, could we possibly
specify it as implementation specific behaviour.

Everything is in place to specify the D_InlineAsm_X86 version
identifier in LDC, but a lot of asm still isn't going to work, due to
reasons like this.

I hope to hear some feedback on how to move on from here.

Thank you all,
Tomas Lindquist Olsen and the LDC Team.



More information about the Digitalmars-d mailing list