www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Final necessary for inline optimization?

reply IGotD- <nise nise.com> writes:
When I'm playing around with different D compilers I get 
different results regarding class method inlining. According most 
information I have seen, you must declare a class method final 
for the compiler to be able inline the method otherwise it will 
be a virtual table call.

Take this simple example.

import std.stdio;
import std.random;

class TestClass
     static auto rnd = Random(42);
     int tt = 3;

     void doStuff()
         tt = uniform(0, 15, rnd);

void main()
     auto c = new TestClass;


     writeln("TestClass is ", c.tt);

The random generator is used here so that CTFE doesn't kick in.

DMD certainly doesn't inline unless I use final (on class or 
doStuff) but when I use LDC, LDC seems to be able to figure out 
that the class isn't derived and inlines it regardless (-O option 
required). I see that LDC generates the method doStuff so it 
could also be that LDC knows which specific class it is (and not 
a derived one) in main and can inline for this particular case. 
Which one is it, LDC recognizes TestClass isn't derived or is 
sure that the class (c) isn't derived in particular? Would that 
mean that the vtable entry for doStuff is created regardless? Any 
other information why LDC do better?

I have previously seen a failed attempt to make final default 
(https://forum.dlang.org/thread/lfqoan$5qq$1 digitalmars.com?page=1) but would
that be necessary. Could the compiler figure out that a class method is final
and manage that optimization by itself?
Oct 19 2019
parent Johan Engelen <j j.nl> writes:
Just a brief answer.

On Saturday, 19 October 2019 at 15:58:08 UTC, IGotD- wrote:
 Which one is it, LDC recognizes TestClass isn't derived or is 
 sure that the class (c) isn't derived in particular?
It is the latter: the optimizer is able to prove that object c has a vtable that is known exactly. Then indexing into that vtable gives a definite function that can then be inlined. Some more info: The (suboptimal) trick that LDC employs is that after the call to `new`, LDC again sets the vtable of the object. It is superfluous, because it is already done by `new`, but `new` is opaque to the optimizer whereas the extra vtable write is not. So after the object creation, the optimizer knows exactly what vtable is used for that object. Now unfortunately, that only works for the first virtual call after `new`. Any opaque function that is called with `c` as parameter, e.g. calling a virtual function of that class will destroy knowledge about what vtable is stored in `c`. Per D language spec, the virtual function cannot overwrite the vtable pointer, but the optimizer does not know that so it assumes it might be overwritten and it no longers knows the contents of the vtable pointer. You can see this happening here: https://d.godbolt.org/z/8ERNhg -Johan
Oct 19 2019