Reputation: 73
So lets say I have 2 functions to choose from based on whether number is even or odd. I came up with this:
(void (*[])()){f1 ,f2}[n%2]();
.
Is it more or less efficient than simply:
n%2 ? f2() : f1();
Upvotes: 3
Views: 106
Reputation: 43327
Profile it; most likely too small to measure.
Assuming a naive compiler, the second will be a lot shorter to execute. But the first is written terribly; could be squashed down to
((n1&1) ? f1 : f2)();
now it's pretty much a toss-up. the first generates something like
test al, 1
jz +3
call f1
jmp +1
call f2
and the second something like
test al, 1
jmp +3
lea rcx, [f1]
jmp +1
lea rcx, [f2]
call rcx
but a good optimizer could flatten that down to
lea rcx, [f1]
test al, 1
cmovcc rcx, f2
call rcx
while all this is true; the initial statement applies. It's most likely too small to measure.
Additional question in comments involving "easier to expand"; well yes. After a surprisingly short number of functions, the array lookup becomes faster. I'm skeptical of things and would not write the array inline but somebody could come along and prove me wrong. If there's more than two I would write
static void (*dispatch_table[])() = {f1 ,f2};
dispatch_table[n % (sizeof(dispatch_table) / sizeof(dispatch_table[0]))]();
This complex mod expression compiles to a compile-time constant; which lets the compiler optimize out the %
to something more performant; it's written as so so that adding more entries doesn't require changing the second argument to %
when adding to the array.
As is being pointed out in comments I didn't handle n
negative. Most RNG sources don't generate negative numbers.
Upvotes: 3
Reputation: 104589
Godbolt to the rescue (64-bit Clang 11.0 with -O3 optimizations): https://godbolt.org/z/MWjPnn
First implementation:
void impl1(int n)
{
(void (*[])()){evenfunc ,oddfunc}[n%2]();
}
mov qword ptr [rsp - 16], offset evenfunc()
mov qword ptr [rsp - 8], offset oddfunc()
mov eax, edi
shr eax, 31
add eax, edi
and eax, -2
sub edi, eax
movsxd rax, edi
jmp qword ptr [rsp + 8*rax - 16] # TAILCALL
Second implementation:
void impl2(int n)
{
n%2 ? oddfunc() : evenfunc();
}
test dil, 1
jne .LBB1_1
jmp evenfunc() # TAILCALL
.LBB1_1:
jmp oddfunc() # TAILCALL
Upvotes: 1