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