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.