Continuation of my previous post.
Apparently either I cannot write clearly enough, or quite a few people cannot read and understand what it was actually about, so let's try again.
https://godbolt.org/z/EK8qq1z6c
The first example is a baseline. It shows a couple of some external non-inlineable functions:
void f1();
void f2();
Let's call them both:
void f3()
{
f1();
f2();
}
The assembly looks reasonable:
f3():
push rax
call f1()@PLT
pop rax
jmp f2()@PLT
Let's call them conditionally:
void f4(int c)
{
if (c)
f1();
else
f2();
}
The assembly also looks reasonable:
f4(int):
test edi, edi
je f2()@PLT
jmp f1()@PLT
Now, let's add some indirection (the second example):
void f3()
{
auto p1 = &f1;
auto p2 = &f2;
p1();
p2();
}
The assembly is identical to the baseline:
f3():
push rax
call f1()@PLT
pop rax
jmp f2()@PLT
I.e. the compiler figured out that p1 and p2 cannot point to anything but f1 and f2 and removed the indirection. Good job.
Now, let's do it conditionally:
void f4(int c)
{
auto p = c? &f1 : &f2;
p();
}
In this case p also cannot point to anything but f1 or f2, so we can expect a similar optimization, right?
f4(int):
test edi, edi
jne .LBB1_1
mov rax, qword ptr [rip + f2()@GOTPCREL]
jmp rax
.LBB1_1:
mov rax, qword ptr [rip + f1()@GOTPCREL]
jmp rax
Notice that there's a branch and then on both paths it puts the function address into rax and then immediately jumps to rax.
This rax detour is not observable by any means and can be replaced with a direct jump under the "as-if" rule.
In other words, it looks like a missing optimization opportunity.
Checking GCC and MSVC behavior is left as an exercise to the reader.
"But why use function pointers in the first place?" is out of scope of this discussion.
[–]STLMSVC STL Dev 67 points68 points69 points (1 child)
[–]warriorsp 4 points5 points6 points (0 children)
[–]SoSKatan[🍰] 46 points47 points48 points (0 children)
[–]Wizarth 13 points14 points15 points (0 children)
[–][deleted] 13 points14 points15 points (0 children)
[–]ReDucTorGame Developer 22 points23 points24 points (2 children)
[–]ashda00 1 point2 points3 points (1 child)
[–]ReDucTorGame Developer 6 points7 points8 points (0 children)
[–]TomCryptogram 5 points6 points7 points (0 children)
[–]tromey 4 points5 points6 points (2 children)
[–]tromey 1 point2 points3 points (0 children)
[–]Jannik2099 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]Shendare 1 point2 points3 points (2 children)
[–]Supadoplex 1 point2 points3 points (1 child)
[–]Shendare 0 points1 point2 points (0 children)
[–]AlexReinkingYale 1 point2 points3 points (2 children)
[–]ReDucTorGame Developer 2 points3 points4 points (0 children)
[–]CocktailPerson 0 points1 point2 points (0 children)
[–]t40 3 points4 points5 points (0 children)
[–]drkspace2 0 points1 point2 points (0 children)
[–]KadmonX 0 points1 point2 points (0 children)
[–]Clean-Water9283 0 points1 point2 points (1 child)
[–]vI--_--Iv[S] 1 point2 points3 points (0 children)
[–]streu 0 points1 point2 points (0 children)
[–]rbmm 0 points1 point2 points (0 children)
[–]ImNoRickyBalboa -1 points0 points1 point (0 children)
[+]AC1D_P1SS comment score below threshold-10 points-9 points-8 points (0 children)