digitalmars.D - Can the D compiler detect final and optimize?
- IGotD- (12/12) Mar 13 2020 A little bit related to that some want class methods to be final
- rikki cattermole (16/16) Mar 13 2020 Why would this be needed?
- IGotD- (10/26) Mar 13 2020 The D programming language by Andrei Alexandrescu. Chapter 6.6.
- Dennis (7/10) Mar 13 2020 The problem is that only at runtime are all the derived classes
- Daniel Kozak (3/13) Dec 25 2020 I believe LTO could do that in some cases
- Johan (9/25) Dec 26 2020 "Whole program optimization", indeed. Search for `fwhole-program`
- Iain Buclaw (23/33) Dec 27 2020 When `scope` is used, the compiler does constant propagation of
- Johan Engelen (30/68) Dec 27 2020 This is already done by LDC (because of overwriting the vtable
- Gregor =?UTF-8?B?TcO8Y2ts?= (4/9) Dec 26 2020 If LTO devirtualizes, then there is the implicit assumption that
- Daniel Kozak (2/17) Dec 25 2020 https://news.ycombinator.com/item?id=17504370
- kindouchoud (4/17) Dec 25 2020 The issue is that just at runtime are for the most part the
A little bit related to that some want class methods to be final by default just like in C++. If I'm not mistaken one benefit of final as default is that the compiler will insert hard coded branches to the method as well as the possibility to do inlining. Are my assumptions correct? Instead of having final as default, can't the compiler itself infer when a class is implicitly final and do the optimizations itself? Benefits would be that a programmer has the possibility to extend about all classes (in C++ would only be possible if class author makes all methods virtual). The final keyword would just mean that a class method is not allowed to be overridden. Is this possible at all?
Mar 13 2020
Why would this be needed? With ldc -O3 the test function can be completely erased: import std; void main() { Foo foo = new Foo; foo.x = 7; test(foo); } void test(Foo foo) { writeln(foo.get); } class Foo { int x; int get() { return x; } }
Mar 13 2020
On Friday, 13 March 2020 at 15:15:50 UTC, rikki cattermole wrote:Why would this be needed? With ldc -O3 the test function can be completely erased: import std; void main() { Foo foo = new Foo; foo.x = 7; test(foo); } void test(Foo foo) { writeln(foo.get); } class Foo { int x; int get() { return x; } }The D programming language by Andrei Alexandrescu. Chapter 6.6. "So final non-override methods are never subjected to indrect calls; instead they enjoy the same calling convention, low overhead and inlining opportunities as regular functions" I think I saw a difference between DMD and LDC previously where LDC actually could in some cases infer that the method is final. If the compiler can infer that a method is final (officially by language standard), then what would the argument for final as default be?
Mar 13 2020
On Friday, 13 March 2020 at 15:08:34 UTC, IGotD- wrote:Instead of having final as default, can't the compiler itself infer when a class is implicitly final and do the optimizations itself?The problem is that only at runtime are all the derived classes known, and by then the code is already compiled. I think the Java Virtual Machine can automatically elide virtual calls by virtue of being a JIT, but for D this would mean either telling the compiler 'assume all derived classes are present in the source files provided here' or doing fancy link-time optimization.
Mar 13 2020
On Fri, Mar 13, 2020 at 5:15 PM Dennis via Digitalmars-d < digitalmars-d puremagic.com> wrote:On Friday, 13 March 2020 at 15:08:34 UTC, IGotD- wrote:I believe LTO could do that in some casesInstead of having final as default, can't the compiler itself infer when a class is implicitly final and do the optimizations itself?The problem is that only at runtime are all the derived classes known, and by then the code is already compiled. I think the Java Virtual Machine can automatically elide virtual calls by virtue of being a JIT, but for D this would mean either telling the compiler 'assume all derived classes are present in the source files provided here' or doing fancy link-time optimization.
Dec 25 2020
On Friday, 25 December 2020 at 19:29:26 UTC, Daniel Kozak wrote:On Fri, Mar 13, 2020 at 5:15 PM Dennis via Digitalmars-d < digitalmars-d puremagic.com> wrote:"Whole program optimization", indeed. Search for `fwhole-program` for GCC and Clang C++ compilers. I don't know how it works for GDC (I think it may have an edge over LDC on this topic), but for LDC we don't tell the optimizer that our vtables are indeed vtables, so I'm not sure if devirtualization works as well as for Clang (which does inform the optimizer about vtables). -JohanOn Friday, 13 March 2020 at 15:08:34 UTC, IGotD- wrote:I believe LTO could do that in some casesInstead of having final as default, can't the compiler itself infer when a class is implicitly final and do the optimizations itself?The problem is that only at runtime are all the derived classes known, and by then the code is already compiled. I think the Java Virtual Machine can automatically elide virtual calls by virtue of being a JIT, but for D this would mean either telling the compiler 'assume all derived classes are present in the source files provided here' or doing fancy link-time optimization.
Dec 26 2020
On Sunday, 27 December 2020 at 00:25:54 UTC, Johan wrote:On Friday, 25 December 2020 at 19:29:26 UTC, Daniel Kozak wrote:When `scope` is used, the compiler does constant propagation of the vtable, because what the optimizer sees is: MyClass __scopeinit = MyClass.init; MyClass* var = &__scopeinit; (var.__vptr + 40)(); If the guts of _d_newclass were also made visible (such as, it was templatized in object.d), then such devirtualization through constant propagation would also occur for simple cases of classes new'd on the GC. Other than that, I'm not sure about other ways to do full devirtualisation of method calls, you are more likely thinking of speculative devirtualization, which looks something like this: if ((&var.foo).funcptr is &MyClass.foo) MyClass.foo(); else var.foo(); If the direct call is inlined, and if the condition is true, then the resulting code may run about 3-5x faster for simple functions. Though these days, I think most CPUs have branch prediction for even indirect calls, so if no optimization happens, the speculative devirtualization like the above will just consume code space and branch prediction buffers.I believe LTO could do that in some cases"Whole program optimization", indeed. Search for `fwhole-program` for GCC and Clang C++ compilers. I don't know how it works for GDC (I think it may have an edge over LDC on this topic), but for LDC we don't tell the optimizer that our vtables are indeed vtables, so I'm not sure if devirtualization works as well as for Clang (which does inform the optimizer about vtables).
Dec 27 2020
On Sunday, 27 December 2020 at 15:22:07 UTC, Iain Buclaw wrote:On Sunday, 27 December 2020 at 00:25:54 UTC, Johan wrote:This is already done by LDC (because of overwriting the vtable ptr after calling _d_newclass, which is redundant but indeed helps with devirtualizing).On Friday, 25 December 2020 at 19:29:26 UTC, Daniel Kozak wrote:When `scope` is used, the compiler does constant propagation of the vtable, because what the optimizer sees is: MyClass __scopeinit = MyClass.init; MyClass* var = &__scopeinit; (var.__vptr + 40)(); If the guts of _d_newclass were also made visible (such as, it was templatized in object.d), then such devirtualization through constant propagation would also occur for simple cases of classes new'd on the GC.I believe LTO could do that in some cases"Whole program optimization", indeed. Search for `fwhole-program` for GCC and Clang C++ compilers. I don't know how it works for GDC (I think it may have an edge over LDC on this topic), but for LDC we don't tell the optimizer that our vtables are indeed vtables, so I'm not sure if devirtualization works as well as for Clang (which does inform the optimizer about vtables).Other than that, I'm not sure about other ways to do full devirtualisation of method calls, you are more likely thinking of speculative devirtualizationNo. I meant that if you know (or assume to know) the full inheritance hierarchy, you can devirtualize this: void foo(A a) { a.some_virtual_call(); }speculative devirtualization, which looks something like this: if ((&var.foo).funcptr is &MyClass.foo) MyClass.foo(); else var.foo(); If the direct call is inlined, and if the condition is true, then the resulting code may run about 3-5x faster for simple functions. Though these days, I think most CPUs have branch prediction for even indirect calls, so if no optimization happens, the speculative devirtualization like the above will just consume code space and branch prediction buffers.Not so: http://johanengelen.github.io/ldc/2016/04/13/PGO-in-LDC-virtual-calls.html The reason is that devirtualization enables other optimizations (like inlining, which in turn creates new profitable optimizations). Rather than doing this whole program optimization with the assumption (!) of knowing the full calls hierarchy, I think it is better to work on preserving vtable knowledge for subsequent method calls, using the knowledge that the object's dynamic type can not change at runtime: although a class method call cannot change the vtable, the GDC and LDC optimizers assume that it may be overwritten because a non-const pointer to the object (the `this` ptr) is passed to the class method. See: https://d.godbolt.org/z/xbajvT ``` A a = new A(); // `scope` is needed for GDC a.foo(); // devirtualized a.foo(); // not devirtualized a.foo(); // not devirtualized ``` -Johan
Dec 27 2020
On Friday, 25 December 2020 at 19:29:26 UTC, Daniel Kozak wrote:On Fri, Mar 13, 2020 at 5:15 PM Dennis via Digitalmars-d < digitalmars-d puremagic.com> wrote:If LTO devirtualizes, then there is the implicit assumption that there is additional code load at runtime, right? So this breaks potentially if you e.g. use dlopen() to load a plugin?[...]I believe LTO could do that in some cases
Dec 26 2020
On Fri, Dec 25, 2020 at 8:29 PM Daniel Kozak <kozzi11 gmail.com> wrote:On Fri, Mar 13, 2020 at 5:15 PM Dennis via Digitalmars-d < digitalmars-d puremagic.com> wrote:https://news.ycombinator.com/item?id=17504370On Friday, 13 March 2020 at 15:08:34 UTC, IGotD- wrote:I believe LTO could do that in some casesInstead of having final as default, can't the compiler itself infer when a class is implicitly final and do the optimizations itself?The problem is that only at runtime are all the derived classes known, and by then the code is already compiled. I think the Java Virtual Machine can automatically elide virtual calls by virtue of being a JIT, but for D this would mean either telling the compiler 'assume all derived classes are present in the source files provided here' or doing fancy link-time optimization.
Dec 25 2020
On Friday, 13 March 2020 at 15:08:34 UTC, IGotD- wrote:A little bit related to that some want class methods to be final by default just like in C++. If I'm not mistaken one benefit of final as default is that the compiler will insert hard coded branches to the method as well as the possibility to do inlining. Are my assumptions correct? Instead of having final as default, can't the compiler itself infer when a class is implicitly final and do the optimizations itself? Benefits would be that a programmer has the possibility to extend about all classes (in C++ would only be possible if class author makes all methods virtual). The final keyword would just mean that a class method is not allowed to be overridden. Is this possible at all?The issue is that just at runtime are for the most part the inferred classes known, and by then the code is as of now arranged.
Dec 25 2020