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...

Reply via email to