Inline assembler in D and LDC, round 2

Frits van Bommel fvbommel at REMwOVExCAPSs.nl
Wed Feb 4 16:32:36 PST 2009


Tomas Lindquist Olsen wrote:
> 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...

Is it really that hard? Can't you just detect this case (non-void 
function without a 'return' at the end but with inline asm inside)?

Since the compiler should know the calling convention[1], the register 
that will contain the return value of the function should be a simple 
lookup (based on target architecture, cc and return type).
Just add that register as an output of the inline asm and return it...

It gets a bit trickier with things like
-----
if (cpu.hasFeatureX())
     asm { ... }
else
     asm { ... }
-----
of course, but storing the value of the register in question into a 
hidden variable and returning its value at the end shouldn't be that hard...

In other words, change every inline asm in a qualifying function to add 
an output of the "return register", store its value into an alloca'd 
stack slot and load & return it at the end of the function.


[1]: Given that LLVM normally handles this, this probably requires an 
extra lookup table in LDC that needs to be kept up-to-date.



More information about the Digitalmars-d mailing list