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