Live data from Hacker News

Function Dispatch Tables in C (2019)

blog.alicegoldfuss.com

21–30 of 52 posts

Re: Function Dispatch Tables in C (2019)

#21

As others say I'm fairly sure switch/case creates a jump table under the hood, and it also checks bounds. Personally, I don't think a static dispatch table like this is a good example. It's really more useful where the dispatch table might be dynamic; for example if a plugin could add more maths functions.

A compiler can generate a jump table. Whether it will is another matter. For a small number of cases or values with large numeric gaps you will most likely get a chain of conditionals.

Re: Function Dispatch Tables in C (2019)

#22

As others say I'm fairly sure switch/case creates a jump table under the hood, and it also checks bounds. Personally, I don't think a static dispatch table like this is a good example. It's really more useful where the dispatch table might be dynamic; for example if a plugin could add more maths functions.

> ...and it also checks bounds.

If you want to get rid of the switch-case bounds check, add a default case with __builtin_unreachable() (or on MSVC: __assume(0)), this hints the optimizer to not create a bounds check before the jump table access. At your own risk of course ;)

Re: Function Dispatch Tables in C (2019)

#23

As others say I'm fairly sure switch/case creates a jump table under the hood, and it also checks bounds. Personally, I don't think a static dispatch table like this is a good example. It's really more useful where the dispatch table might be dynamic; for example if a plugin could add more maths functions.

A compiler can generate a jump table. Whether it will is another matter. For a small number of cases or values with large numeric gaps you will most likely get a chain of conditionals.

IME the popular compilers (clang, gcc, msvc) are really aggressive about generating a jump table though, e.g. if you have continuous ranges with gaps between them, it will create a jump table for each range, not simply fall back to a dumb sequence of tests.

Re: Function Dispatch Tables in C (2019)

#24
post #5

Definitely can be useful, but keep in mind that performance will usually be worse for function tables.

Why? And, if this is the case, why then do compilers turn switch statements into function tables?

A jump table made of function pointers has more runtime overhead than a switch-case jump table because the latter directly jumps into machine code snippets within the same function, and those snippets don't have the function prologues/epilogues. And function pointers are also often an "optimization barrier" where the compiler can't inline to get rid of the epilogue and prologue.

Re: Function Dispatch Tables in C (2019)

#25
post #20

Earlier quoted context omitted.

Why? And, if this is the case, why then do compilers turn switch statements into function tables?

While compilers do turn switch statements into jump tables, in this case storing function pointers and calling them you add the additional call overhead of saving registers, setting up the stack, etc in the function prolog and epilog.

That call overhead is there in then code using "if-else" logic to determine which functions to call, also, though.

So I still don't see your claim as being accurate.

Re: Function Dispatch Tables in C (2019)

#26

Earlier quoted context omitted.

Whats the performance cost exactly?

Modern CPUs with pipelining, branch prediction, speculative execution, caching do best with fewer jumps, small code size, predictable jump targets, sequential access. A tight loop of "jump to the address i just loaded from this 64 bit quantity" throws a total wrench in the middle of it and will have those mechanisms stall. Imagine a sorting algorithm with a jump into a callback to compare the elements. Then compare w…

I think you are constructing a straw man argument. The jump-table approach is just as likely to be a candidate for the optimization you claim will get in the way, as the code using if/switch statements. In fact, the compiler can see that simple call through the jump table and optimize it even better - maybe even by inlining.

The question is, how are you sure this isn't happening? The answer is, you're not - unless you examine the code your compiler is emitting, such claims are specious.

Re: Function Dispatch Tables in C (2019)

#27
post #20

Earlier quoted context omitted.

While compilers do turn switch statements into jump tables, in this case storing function pointers and calling them you add the additional call overhead of saving registers, setting up the stack, etc in the function prolog and epilog.

That call overhead is there in then code using "if-else" logic to determine which functions to call, also, though. So I still don't see your claim as being accurate.

...not quite: the if-else (or switch-case) can usually inline the called function, which gets rid of the epilogue/prologue and opens up more optimization opportunities.

Re: Function Dispatch Tables in C (2019)

#28

Earlier quoted context omitted.

Modern CPUs with pipelining, branch prediction, speculative execution, caching do best with fewer jumps, small code size, predictable jump targets, sequential access. A tight loop of "jump to the address i just loaded from this 64 bit quantity" throws a total wrench in the middle of it and will have those mechanisms stall. Imagine a sorting algorithm with a jump into a callback to compare the elements. Then compare w…

I think you are constructing a straw man argument. The jump-table approach is just as likely to be a candidate for the optimization you claim will get in the way, as the code using if/switch statements. In fact, the compiler can see that simple call through the jump table and optimize it even better - maybe even by inlining. The question is, how are you sure this isn't happening? The answer is, you're not - unless yo…

That's exactly why you're supposed to examine the compiler output, and doing this will tell you that function pointer jump tables are often not optimized that way. There's a good reason why emulators / virtual machines use switch-case or computed-goto instead of function pointer jump tables for opcode dispatching.

Re: Function Dispatch Tables in C (2019)

#30
post #20

Earlier quoted context omitted.

While compilers do turn switch statements into jump tables, in this case storing function pointers and calling them you add the additional call overhead of saving registers, setting up the stack, etc in the function prolog and epilog.

That call overhead is there in then code using "if-else" logic to determine which functions to call, also, though. So I still don't see your claim as being accurate.

My comparison is vis-a-vis an array of function pointers as described in the article vs a compiler-generated switch jump table with inlined bodies that the compiler will always generate with a switch statement, rather than in comparison to an if-else tree: there is no function being generated, so there is no function prolog or epilog.
Post reply on HN