Technology1 min read

Switch Lowering in GCC

By · Published by Everything Blog

In short

When optimizing switch statements under the -O3 flag, GCC determines whether to generate jump tables or decision trees based on case label density. The compiler can isolate distant outliers into direct branches while grouping closely packed values into localized jump tables, accommodating constant offsets automatically. However, the compiler may bypass jump tables if multiple labels share code or if it misses mathematical simplifications on regularly spaced sparse inputs. Most of these behavioral patterns also extend to Clang, which differs mainly in how it handles bitset lowering.

Key points

  • GCC falls back to comparison trees instead of jump tables when switch case values are too…: GCC falls back to comparison trees instead of jump tables when switch case values are too sparse.
  • Shared code blocks across multiple labels can cause GCC to reject jump tables despite ade…: Shared code blocks across multiple labels can cause GCC to reject jump tables despite adequate overall value density.
  • Clang shares most of GCC's switch lowering strategies with the notable exception of bitse…: Clang shares most of GCC's switch lowering strategies with the notable exception of bitset lowering implementation.

Sources checked by our analysis pipeline: 1

2024-01-14

We have seen in a previous post that switch statements are more complex than they seem. The compiler is able to implement them as a decision tree (even though maybe it shouldn't). Is that everything it can do?

In this post, I'll focus on gcc

. All optimizations, except the bitset lowering, translate to clang. I'll be using the -O3

optimization flag unless indicated otherwise.

I've also slightly edited gcc

code and removed certain assertions for brevity.

Let us start with a simple example.

A function that takes two integers x

and val

. Depending on the value of x

, it calls a corresponding function (f0

, f1

, and so forth) with val

as an argument and returns the result.

Were we to implement this manually, we'd would use an array of function pointers, where the input serves as the index into the array.

int ;

int ;

int ;

int ;

int ;

int

compact:

mov eax, edi

mov edi, esi

cmp eax, 4

ja .L2

jmp [QWORD PTR .L4[0+rax*8]]

.L4:

.quad .L8

.quad .L7

.quad…

Technology