Day 23 of Advent of Compiler Optimisations!

Switch statements compile to jump tables, right? Well... sometimes. But what happens when your five-case switch becomes pure arithmetic? Or when checking for whitespace turns into a single mysterious constant and some bit manipulation? Turns out compilers have a whole bag of tricks beyond the textbook answer.

Read more: https://xania.org/202512/23-switching-it-up
Watch: https://youtu.be/aSljdPafBAw

#AoCO2025

Switching it up a bit — Matt Godbolt’s blog

Taking a look at the various ways the compiler can optimise switch statements

@mattgodbolt regarding the mov eax, 0 from gcc: it is followed by a cmovb, doing a xor there would affect the relevant ALU flags.
@tiwe yes! The top pinned comment in the YT video corrects that : I missed that completely :)
@mattgodbolt i missed the comments there, most of the time i use an rss reader for notifications about new videos and yt-dlp/mpv for watching
@tiwe don't worry most of the other commenters on YouTube also missed the comment :-)
@mattgodbolt Something I've been trying to figure out is why the jump table in do_a_thing_dense generates a jump table where each branch consists of a single jump instruction. Why not place the function pointers into the jump table and then accomplish it with a single indirect branch?
@mattgodbolt For instance, why do these not produce the same code? https://gcc.godbolt.org/z/3Mshzs4Mz
Compiler Explorer - C++ (x86-64 gcc 15.2)

void func0(), func1(), func2(), func3(), func4(); void do_a_thing_dense(unsigned x) { switch (x) { case 0: func0(); break; case 1: func1(); break; case 2: func2(); break; case 3: func3(); break; case 4: func4(); break; } } void do_a_thing_explicit_jump(unsigned x) { static void(*jt[])() = {func0, func1, func2, func3, func4}; jt[x](); }

@arlencox Great question (I made a small change to get the two versions to better agree: https://gcc.godbolt.org/z/KrfhjTKca but they're still demonstrating the behaviour you mention).

I honestly don't have a good instinct as to why it would do this: it seems obvious that it should remove a layer of indirection. Initially I thought "maybe something about linker fixups" but no, that would apply to the jump table too... so ..

I'm stumped :) Great question to ask on the compiler lists. Clang does something similar too!

Compiler Explorer - C++ (x86-64 gcc 15.2)

void func0(), func1(), func2(), func3(), func4(); void do_a_thing_dense(unsigned x) { switch (x) { case 0: func0(); return; case 1: func1(); return; case 2: func2(); return; case 3: func3(); return; case 4: func4(); return; } __builtin_unreachable(); } void do_a_thing_explicit_jump(unsigned x) { static void(*jt[])() = {func0, func1, func2, func3, func4}; jt[x](); }