On Thursday, 25 August 2016 at 14:42:28 UTC, Basile B. wrote:
On Thursday, 25 August 2016 at 11:16:52 UTC, Cecil Ward wrote:
[...]
I'll add
* create temporaries based on the const function attribute.
I don't know why but I believed that it was already the case.
After disassembling a short test with DMD and LDMD2 it appears
clearly that this is not true:
°°°°°°°°°°°°°°°°°°°°°°°°°°
struct Foo
{
immutable _u = 8;
int foo() const
{
return 8 * _u;
}
}
int use(ref const(Foo) foo)
{
return foo.foo() + foo.foo();
}
°°°°°°°°°°°°°°°°°°°°°°°°°°
disasm of use (LDC2 via LDMD2, -O -release)
0000000000402930h sub rsp, 18h
0000000000402934h mov qword ptr [rsp+10h], rdi
0000000000402939h call 00000000004028F0h ; (Foo.foo)
000000000040293Eh mov rdi, qword ptr [rsp+10h]
0000000000402943h mov dword ptr [rsp+0Ch], eax
0000000000402947h call 00000000004028F0h ; (Foo.foo)
000000000040294Ch mov ecx, dword ptr [rsp+0Ch]
0000000000402950h add ecx, eax
0000000000402952h mov eax, ecx
0000000000402954h add rsp, 18h
0000000000402958h ret
But Foo.foo constness guarantees that Foo state is not
modified. So the result of the first CALL could be cached in a
temporary and reused instead of the second CALL. This would
help for example in loops when a getter function is called to
know the iteration count.
The problem of the non-caching of appropriate function calls is
not confined to methods. It also is observable when calling
explicitly pure-marked external functions, eg. my_pure() +
my_pure() makes two calls. (Checked in GCC -O3, with an extern
pure-marked function.)
This is often covered up by inlining with full expansion, as
non-extern functions don't show this.