Re: How to overload member function pointer and a regualr member function
On Wednesday, 26 April 2017 at 08:24:08 UTC, Basile B. wrote: On Tuesday, 25 April 2017 at 18:58:58 UTC, Ali Çehreli wrote: On 04/25/2017 11:54 AM, Ali Çehreli wrote: My analysis is wrong because that writefln() is for the bar(float) overload but I still think what you want is achieved. Ali No it's ok, it works. The additional indirection is well avoided: Let's take this module: == #!dmd -release -inline -O module runnable; struct Foo { private void function(int,float) _bar; void bar(float){} pragma(inline, false) void bar(int i, float f){_bar(i,f);} } struct FooInline { private void function(int,float) _bar; void bar(float){} pragma(inline, true) void bar(int i, float f){_bar(i,f);} } void testInlined(ref FooInline foo) { foo.bar(0,0); } void test(ref Foo foo) { foo.bar(0,0); } void main() { import disassembler, std.stdio; disassembler.symbolTable.addModule!runnable; prettyDisasm().writeln; prettyDisasm(, 2).writeln; // dig up to 2 levels, required for the indir. } == and looks at the output: ;--- SUB 00459970h --- ; NAMED: testInlined 00459970h push rbp 00459971h mov rbp, rsp 00459974h sub rsp, 20h 00459978h mov qword ptr [rbp-08h], rdi 0045997Ch xor edi, edi 0045997Eh mov dword ptr [rbp-20h], edi 00459981h movss xmm0, dword ptr [rbp-20h] 00459986h mov rax, qword ptr [rbp-08h] 0045998Ah call qword ptr [rax] 0045998Dh mov rsp, rbp 00459990h pop rbp 00459991h ret ;- ;--- SUB 00459934h --- ; XREFS: [004599A6h] 00459934h push rbp 00459935h mov rbp, rsp 00459938h sub rsp, 10h 0045993Ch mov qword ptr [rbp-08h], rdi 00459940h mov rdi, rsi 00459943h mov rax, qword ptr [rbp-08h] 00459947h call qword ptr [rax] 0045994Ah mov rsp, rbp 0045994Dh pop rbp 0045994Eh ret ;- ;--- SUB 00459994h --- ; NAMED: test 00459994h push rbp 00459995h mov rbp, rsp 00459998h sub rsp, 10h 0045999Ch xor esi, esi 0045999Eh mov dword ptr [rbp-10h], esi 004599A1h movss xmm0, dword ptr [rbp-10h] 004599A6h call 00459934h 004599ABh mov rsp, rbp 004599AEh pop rbp 004599AFh ret ;- - testInlined() contains only the delegate call. (call qword ptr [rax]) - test() contains a call (call 00459934h) which contains the delegate call (call qword ptr [rax]) Actually i've even had to add (pragma inline false) to show the difference since DMD inlined automatically bar() in test(). Guys, you're great! Thanks a lot!
Re: How to overload member function pointer and a regualr member function
On Tuesday, 25 April 2017 at 18:58:58 UTC, Ali Çehreli wrote: On 04/25/2017 11:54 AM, Ali Çehreli wrote: My analysis is wrong because that writefln() is for the bar(float) overload but I still think what you want is achieved. Ali No it's ok, it works. The additional indirection is well avoided: Let's take this module: == #!dmd -release -inline -O module runnable; struct Foo { private void function(int,float) _bar; void bar(float){} pragma(inline, false) void bar(int i, float f){_bar(i,f);} } struct FooInline { private void function(int,float) _bar; void bar(float){} pragma(inline, true) void bar(int i, float f){_bar(i,f);} } void testInlined(ref FooInline foo) { foo.bar(0,0); } void test(ref Foo foo) { foo.bar(0,0); } void main() { import disassembler, std.stdio; disassembler.symbolTable.addModule!runnable; prettyDisasm().writeln; prettyDisasm(, 2).writeln; // dig up to 2 levels, required for the indir. } == and looks at the output: ;--- SUB 00459970h --- ; NAMED: testInlined 00459970h push rbp 00459971h mov rbp, rsp 00459974h sub rsp, 20h 00459978h mov qword ptr [rbp-08h], rdi 0045997Ch xor edi, edi 0045997Eh mov dword ptr [rbp-20h], edi 00459981h movss xmm0, dword ptr [rbp-20h] 00459986h mov rax, qword ptr [rbp-08h] 0045998Ah call qword ptr [rax] 0045998Dh mov rsp, rbp 00459990h pop rbp 00459991h ret ;- ;--- SUB 00459934h --- ; XREFS: [004599A6h] 00459934h push rbp 00459935h mov rbp, rsp 00459938h sub rsp, 10h 0045993Ch mov qword ptr [rbp-08h], rdi 00459940h mov rdi, rsi 00459943h mov rax, qword ptr [rbp-08h] 00459947h call qword ptr [rax] 0045994Ah mov rsp, rbp 0045994Dh pop rbp 0045994Eh ret ;- ;--- SUB 00459994h --- ; NAMED: test 00459994h push rbp 00459995h mov rbp, rsp 00459998h sub rsp, 10h 0045999Ch xor esi, esi 0045999Eh mov dword ptr [rbp-10h], esi 004599A1h movss xmm0, dword ptr [rbp-10h] 004599A6h call 00459934h 004599ABh mov rsp, rbp 004599AEh pop rbp 004599AFh ret ;- - testInlined() contains only the delegate call. (call qword ptr [rax]) - test() contains a call (call 00459934h) which contains the delegate call (call qword ptr [rax]) Actually i've even had to add (pragma inline false) to show the difference since DMD inlined automatically bar() in test().
Re: How to overload member function pointer and a regualr member function
On 04/25/2017 11:54 AM, Ali Çehreli wrote: > _Dmain: > pushRBP > movRBP,RSP > subRSP,010h > movRAX,_D6deneme4funcFifZv@GOTPCREL[RIP] > mov-010h[RBP],RAX > movssXMM0,FLAT:.rodata[00h][RIP] > movss-8[RBP],XMM0 > leaRDX,_TMP0@PC32[RIP] > movEDI,0Eh > movRSI,RDX > movssXMM0,-8[RBP] > call _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv@PLT32 > movEAX,02Ah > movssXMM1,FLAT:.rodata[00h][RIP] > movss-4[RBP],XMM1 > movRDI,RAX > movssXMM0,-4[RBP] > callqword ptr -010h[RBP] > xorEAX,EAX > leave > ret > add[RAX],AL > .text._Dmainends > > The call to jumbled writefln() is a direct call inside func(): > > call _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv@PLT32 My analysis is wrong because that writefln() is for the bar(float) overload but I still think what you want is achieved. Ali
Re: How to overload member function pointer and a regualr member function
On 04/25/2017 11:28 AM, ParticlePeter wrote: > On Tuesday, 25 April 2017 at 16:27:43 UTC, Basile B. wrote: >> with pragma(inline, true), the function body should be injected at the >> call sites. > > This would not help I fear, the body of the function pointer is unknown > in an external lib. I rather hoped that the compiler "sees" the > parameter forwarding to the fp and is able to directly call it. Best > thing would be for both overloads, but I would not know how to verify this. pragma(inline, true) works because all you need inlined in this case is the body of bar(int, float). The compiler does call the function pointer directly. import std.stdio; struct Foo1 { private void function(int,float) _bar; void bar(float f) { pragma(inline, true); writefln("Called with %s", f); } void bar(int i, float f) { pragma(inline, true); _bar(i,f); } } void func(int i, float f) { writefln("Called with %s and %s", i, f); } void main() { auto f = Foo1(); f.bar(1.5); f.bar(42, 2.5); } Compile with -inline (and perhaps with -O): dmd -inline deneme.d Generate the disassembly with obj2asm that comes with dmd (or with any other disassembly tool): obj2asm deneme.o > deneme.asm You can open deneme.asm in an editor and search for function "_Dmain:" in it. Here is what my dmd 2.074 produced: _Dmain: pushRBP mov RBP,RSP sub RSP,010h mov RAX,_D6deneme4funcFifZv@GOTPCREL[RIP] mov -010h[RBP],RAX movss XMM0,FLAT:.rodata[00h][RIP] movss -8[RBP],XMM0 lea RDX,_TMP0@PC32[RIP] mov EDI,0Eh mov RSI,RDX movss XMM0,-8[RBP] call _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv@PLT32 mov EAX,02Ah movss XMM1,FLAT:.rodata[00h][RIP] movss -4[RBP],XMM1 mov RDI,RAX movss XMM0,-4[RBP] callqword ptr -010h[RBP] xor EAX,EAX leave ret add [RAX],AL .text._Dmainends The call to jumbled writefln() is a direct call inside func(): call _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv@PLT32 So, you're good... :) Ali
Re: How to overload member function pointer and a regualr member function
On Tuesday, 25 April 2017 at 16:27:43 UTC, Basile B. wrote: On Tuesday, 25 April 2017 at 15:43:48 UTC, ParticlePeter wrote: On Tuesday, 25 April 2017 at 09:50:14 UTC, Basile B. wrote: On Monday, 24 April 2017 at 16:46:21 UTC, ParticlePeter wrote: Thanks for your reply, but that's what I would like to avoid, the additional indirection to call the function pointer with the original argument count. Oops, i can believe i didn't read the last part of your question. Do you have any idea about the likelihood of the compiler removing this indirection as an optimizations? with pragma(inline, true), the function body should be injected at the call sites. This would not help I fear, the body of the function pointer is unknown in an external lib. I rather hoped that the compiler "sees" the parameter forwarding to the fp and is able to directly call it. Best thing would be for both overloads, but I would not know how to verify this.
Re: How to overload member function pointer and a regualr member function
On Tuesday, 25 April 2017 at 09:50:14 UTC, Basile B. wrote: On Monday, 24 April 2017 at 16:46:21 UTC, ParticlePeter wrote: I would like to have this kind of struct: struct Foo { private int i; void function( int i, float f ) bar; // will be defined at runtime void bar( float f ) { bar( i, f ); } } [...] How else can I get the required behavior? Like this: struct Foo1 { private void function(int,float) _bar; void bar(float){} void bar(int i, float f){_bar(i,f);} } Thanks for your reply, but that's what I would like to avoid, the additional indirection to call the function pointer with the original argument count. Do you have any idea about the likelihood of the compiler removing this indirection as an optimizations?
Re: How to overload member function pointer and a regualr member function
On Monday, 24 April 2017 at 16:46:21 UTC, ParticlePeter wrote: I would like to have this kind of struct: struct Foo { private int i; void function( int i, float f ) bar; // will be defined at runtime void bar( float f ) { bar( i, f ); } } [...] How else can I get the required behavior? Like this: struct Foo1 { private void function(int,float) _bar; void bar(float){} void bar(int i, float f){_bar(i,f);} } Or like this: struct Foo2 { private void function(int,float) _bar; void bar(float) {} void function(int,float) bar() {return _bar;} } First solution looks better: (new Foo2).bar()(0,0f) // less good (new Foo1).bar(0,0f) // better
How to overload member function pointer and a regualr member function
I would like to have this kind of struct: struct Foo { private int i; void function( int i, float f ) bar; // will be defined at runtime void bar( float f ) { bar( i, f ); } } But apparently the function pointer and the member function cannot have the same name: Error: function main.Foo.bar conflicts with variable main.Foo.bar ... I tried with an inner struct: struct Foo { private int i; void function( int i, float f ) bar; // will be defined at runtime private struct Inner { void bar( float f ) { bar( i, f ); } } Inner inner; } But this time I get following error: Error: need 'this' for 'i' of type 'int' What does this message tell me? Should the inner struct not be able to access Foo.i? How else can I get the required behavior? I would prefer to avoid another indirection like this: struct Foo { private int i; void function( int i, float f ) bar; // will be defined at runtime void baz( float f ) { bar( i, f ); } void baz( int ii, float f ) { bar( ii, f ); } }