Inlining asm functions
Frits van Bommel
fvbommel at REMwOVExCAPSs.nl
Thu Jun 11 17:05:12 PDT 2009
Brad Roberts wrote:
> On Thu, 11 Jun 2009, Frits van Bommel wrote:
>> Note that for LDC, an even more optimal arrangement is something like[1]:
>> -----
>> version(LDC)
>> import ldc.llvmasm;
>>
>> creal expi(real y) {
>> return __asm!(creal)("fsincos", "={st(0)},={st(1)},0", y);
>> }
>> -----
>
> My appologies if I cut too much context, but one of the things Walter
> explicitly wanted with D's asm syntax was that it be portable across
> compilers. Having to have special syntax for each compiler is a problem.
The problem with the standard asm syntax is that it only allows access to
variables in memory (except in naked functions), while it would often be
beneficial for the compiler to load values into registers instead.
Currently, "standard asm" can lead to silly sequences like storing a value to
the stack (outside the asm), then immediately loading it again (inside the asm),
possibly to the same register...
I suppose this could be worked around by allowing the compiler to "strip off"
loads from variables at the start of asm and stores to variables at the end, and
replace them with register constraints. (And/or allow it to put the variable in
a register altogether when all instructions that use it allow a register operand
too and the register is otherwise unused by the inline asm)
This "Do what I mean, not what I say" is not allowed by the specification for
the standard asm syntax, I think. (Though both GDC and LDC already do some
gymnastics that come close to this since IIRC both need to translate
"somevar[EBP]" into something their respective backends can understand, which
may or may not result in actually indexing off of EBP in the resulting code)
(Can you tell I was thinking about something like that when Tomas implemented
the __asm hack? :) )
Or does D have an "as if" rule like C++ does? (i.e.: the compiler is allowed to
transform code any way it likes, as long as observable behavior is "as if" it
did what the programmer specified)
And if so, does it apply to inline asm too?
Note that GDC actually took a similar approach as LDC did by allowing an
alternate asm syntax in addition to the standard one, and it uses explicit
constraints instead of requiring the programmer to manually load and store to
variables.
Another benefit of the LDC asm syntax is that it maps 1-to-1 onto the LLVM
inline asm primitive, so it needs no adjustment to the LDC source to support
ARM, Mips, PowerPC, or any other platform LLVM supports but for which no inline
asm is implemented otherwise.
So while I agree a standard asm syntax is desirable, I just think the current
syntax may not be the best one for all jobs.
> I strongly agree that functions using asm should be inlineable.
This is very hard to allow without an explicit signal that it's okay (like
pragma(allow_inline)) with the standard syntax because it would require the
compiler to check that it's safe, meaning it needs a pretty good understanding
of each and every asm instruction as opposed to just being able to translate it
into binary code or AT&T syntax, which is what current compilers do.
(Both GDC and LDC already do some analysis of the asm while translating to AT&T
to figure out what registers are modified so they can put together a clobber
list, but that's not enough to allow inlining)
The fact that everything in std.intrinsic could easily be replaced by an asm
one-liner[1] if they could only be inlined tells me Walter hasn't figured out
how to do it either[2]...
[1]: Plus either set-up & tear-down or constraints, that is.
[2]: Though this may have to do with the internals of the DMD inliner, which is
a whole other topic...
More information about the Digitalmars-d
mailing list