Switch Lowering in GCC
Posted by signa11 11 hours ago
Comments
Comment by erk__ 4 minutes ago
Comment by LarsKrimi 9 hours ago
It could not because that would ensure that 7 values for each case would be handled by function calls instead of the default case - 0/8 is 0, but 3/8 is also 0
Comment by rep_lodsb 7 hours ago
cmp eax,40
ja <return 0>
test eax,7
jnz <return 0>
jmp JumpTable[rax]Comment by ack_complete 25 minutes ago
mov ecx, eax
ror eax, 3
cmp eax, 5
ja <return 0>
jmp JumpTable[rcx]Comment by LarsKrimi 6 hours ago
A rough benchmark of a version of that against the original shows it to be close to twice as fast for unpredictable input with GCC (4.5 ns vs 2.72 ns) on my old machine. With predictable input where x values often are the same the original version is quicker
int sparse_8_jump(int x, int val) {
unsigned int idx = (unsigned int)x >> 3;
if (idx > 5)
return 0;
if (x & 7)
return 0;
switch (idx) {
case 0:
return f0(val);
case 1:
return f1(val);
case 2:
return f2(val);
case 3:
return f3(val);
case 5:
return f4(val);
default:
return 0;
}
}Comment by Findecanor 7 hours ago
... unless the size of immediate parameters would have affected code size. In the example code however, all constants fit in an `imm8` parameter to `cmp`.
Comment by rurban 9 hours ago
Comment by jcranmer 3 hours ago
Perfect hashing for switch tables is useful mostly for large, sparse switches, but hot large, sparse switches are rare, and the closest examples I can think of (e.g., parse tables) are themselves likely generated from other tools, which could itself be changed in lieu of the compiler. It really doesn't come across as a useful optimization to try implementing in a compiler.
Comment by bobmcnamara 2 hours ago
Comment by flohofwoe 1 hour ago
Comment by nh2 6 hours ago
For example, my bug report that `+= 2` is broken has not been acknowledged (read?) by anyone for 3 years:
const size_t n = 13; // triggers the issue
#pragma omp parallel for
for (uint32_t i = 0; i < n; i += 2) { // counts PAST 13!
https://github.com/llvm/llvm-project/issues/70687Comment by rurban 6 hours ago
Comment by stefan_ 3 hours ago
Ahh, there it is! This issue isn't being tended to because it will resolve itself with the imminent death of OpenMP.
Comment by jamiejquinn 58 minutes ago
Comment by RossBencina 7 hours ago
Comment by rurban 5 hours ago
Comment by Sopel 3 hours ago
Comment by garaetjjte 4 hours ago
Comment by tester756 8 hours ago
>The LLVM patch was rejected a decade ago
And what was the reasoning?
Comment by ahartmetz 7 hours ago
Comment by saagarjha 6 hours ago
Comment by ahartmetz 3 hours ago
Comment by p-t 2 hours ago
Comment by tsukikage 8 hours ago
Comment by Findecanor 7 hours ago
Each `jmp` to f0..fX is an optimisation of a `call` and a `ret`, and probably done in a separate pass after the switch-case code has already been expanded.
The `mov edi, esi` at the top of the function is also an optimisation, most likely done during the register allocation pass. This was only possible because all functions take the same value in the same register. Otherwise, there would probably have been also a `mov` before each of the calls.
Comment by andikleen2 6 hours ago
Comment by yksalun 7 hours ago
Comment by Andi 8 hours ago
Comment by sylware 9 hours ago
Comment by ahartmetz 7 hours ago
It is still possible that a later pass arranges jump targets to avoid false sharing of their entries (addresses) in prediction mechanisms and such.
Comment by sylware 7 hours ago
Obvsiously engaging in pleasing as much as it can speculative/BTB hardware (to the cost of memory tables!)
Comment by arsalan17 10 hours ago
Comment by yarkwright 4 hours ago