Fixture 106
switch shapes dense sparse
C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
Three switch shapes that lower differently: a dense contiguous range becomes a jump table, a sparse one becomes a comparison tree, and a range with a single outlier becomes a hybrid.
#include <stdint.h>
/* Three switch shapes that lower differently: a dense contiguous range becomes
* a jump table, a sparse one becomes a comparison tree, and a range with a
* single outlier becomes a hybrid. */
__attribute__((noinline)) int32_t dense_switch(int32_t selector) {
switch (selector) {
case 0: return 11;
case 1: return 22;
case 2: return 33;
case 3: return 44;
case 4: return 55;
case 5: return 66;
case 6: return 77;
case 7: return 88;
default: return -1;
}
}
__attribute__((noinline)) int32_t sparse_switch(int32_t selector) {
switch (selector) {
case -1000: return 1;
case 7: return 2;
case 1009: return 3;
case 65536: return 4;
case 1000000: return 5;
default: return -1;
}
}
__attribute__((noinline)) int32_t hybrid_switch(int32_t selector) {
int32_t total = 0;
switch (selector) {
case 1:
case 2:
case 3:
total = 10;
break;
case 4:
total = 20;
__attribute__((fallthrough));
case 5:
total += 5;
break;
case 999999:
total = 30;
break;
default:
total = -1;
break;
}
return total;
} Recovered C
Generated by glaurung decompile --style decbench at b47f6b43.
baseline.json records the result after recompiling the C and calling it beside the
original with seeded inputs.
clang -O0
3/3dense_switch pass 25 lines
// glaurung: dense_switch @ 0x1100
int32_t dense_switch(int32_t arg0) {
// x86-64 prologue: save rbp
switch ((unsigned int)(arg0)) {
case 0:
return (unsigned int)(11);
case 1:
return (unsigned int)(22);
case 2:
return (unsigned int)(33);
case 3:
return (unsigned int)(44);
case 4:
return (unsigned int)(55);
case 5:
return (unsigned int)(66);
case 6:
return (unsigned int)(77);
case 7:
return (unsigned int)(88);
default:
return (unsigned int)(-1);
}
// x86-64 epilogue: restore rbp
} hybrid_switch pass 27 lines
// glaurung: hybrid_switch @ 0x1250
int32_t hybrid_switch(int32_t arg0) {
int total;
int var9;
// x86-64 prologue: save rbp
total = 0;
if (((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 1)))) < (unsigned long)(3))) {
return 10;
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 4))) == 0)) {
var9 = 25;
return 25;
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 5))) == 0)) {
var9 = ((unsigned int)(total) + 5);
total = var9;
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
}
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 0xf423f))) == 0)) {
return 30;
} else {
return (unsigned int)(-1);
}
}
}
} sparse_switch pass 25 lines
// glaurung: sparse_switch @ 0x11a0
int32_t sparse_switch(int32_t arg0) {
// x86-64 prologue: save rbp
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) + 1000))) == 0)) {
return 1;
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 7))) == 0)) {
return 2;
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 1009))) == 0)) {
return 3;
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 0x10000))) == 0)) {
return 4;
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - 0xf4240))) == 0)) {
return 5;
} else {
return (unsigned int)(-1);
}
}
}
}
}
} clang -O2
3/3dense_switch pass 4 lines
// glaurung: dense_switch @ 0x1100
int32_t dense_switch(int32_t arg0) {
return (((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)(8)) ? (unsigned long)((unsigned int)(((arg0 + ((unsigned long)((unsigned int)((arg0 + (arg0 * 4)))) * 2)) + 11))) : 0xffffffff);
} hybrid_switch pass 22 lines
// glaurung: hybrid_switch @ 0x1170
int32_t hybrid_switch(int32_t arg0) {
int total;
long var2;
if (((((unsigned long)((unsigned int)(arg0)) == 3) | ((long)(arg0) < 3)) != 0)) {
if (((unsigned long)(3) <= (unsigned long)((unsigned long)((unsigned int)((arg0 - 1)))))) {
return 0xffffffff;
}
return 10;
}
if (((unsigned long)((unsigned int)(arg0)) == 0xf423f)) {
return 30;
}
var2 = (unsigned long)((unsigned int)(arg0));
if (((unsigned long)((unsigned int)(arg0)) != 5)) {
if (((unsigned long)((unsigned int)(arg0)) != 4)) {
return 0xffffffff;
}
var2 = 25;
}
return (unsigned int)(var2);
} sparse_switch pass 24 lines
// glaurung: sparse_switch @ 0x1120
int32_t sparse_switch(int32_t arg0) {
long ret;
if (((((unsigned long)((unsigned int)(arg0)) == 1008) | ((long)(arg0) < 1008)) == 0)) {
if (((unsigned long)((unsigned int)(arg0)) == 1009)) {
return 3;
}
if (((unsigned long)((unsigned int)(arg0)) == 0x10000)) {
return 4;
}
if (((unsigned long)((unsigned int)(arg0)) != 0xf4240)) {
return 0xffffffff;
}
return 5;
}
ret = 1;
if (((unsigned long)((unsigned int)(arg0)) == 0xfffffc18)) {
return ret;
}
if (((unsigned long)((unsigned int)(arg0)) != 7)) {
return 0xffffffff;
}
return 2;
} gcc -O0
3/3dense_switch pass 25 lines
// glaurung: dense_switch @ 0x10f9
int32_t dense_switch(int32_t arg0) {
// x86-64 prologue: save rbp
switch ((unsigned long)((unsigned int)(arg0))) {
case 0:
return 11;
case 1:
return 22;
case 2:
return 33;
case 3:
return 44;
case 4:
return 55;
case 5:
return 66;
case 6:
return 77;
case 7:
return 88;
default:
return 0xffffffff;
}
// x86-64 epilogue: restore rbp
} hybrid_switch pass 43 lines
// glaurung: hybrid_switch @ 0x11e9
int32_t hybrid_switch(int32_t arg0) {
int total;
long t136;
// x86-64 prologue: save rbp
total = 0;
if (((unsigned long)((unsigned int)(arg0)) == 0xf423f)) {
return 30;
}
if (((((unsigned long)((unsigned int)(arg0)) == 0xf423f) | ((long)(arg0) < 0xf423f)) == 0)) {
L_124e: ;
total = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
}
if (((unsigned long)((unsigned int)(arg0)) == 5)) {
t136 = ((unsigned long)((unsigned int)(total)) + 5);
total = t136;
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
}
if (((((unsigned long)((unsigned int)(arg0)) == 5) | ((long)(arg0) < 5)) == 0)) {
total = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
}
if (((((unsigned long)((unsigned int)(arg0)) == 3) | ((long)(arg0) < 3)) == 0)) {
if (((unsigned long)((unsigned int)(arg0)) == 4)) {
t136 = 25;
total = 25;
} else {
total = -1;
}
} else {
if (((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0)) == 0)) {
total = 10;
} else {
goto L_124e;
}
}
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} sparse_switch pass 20 lines
// glaurung: sparse_switch @ 0x116d
int32_t sparse_switch(int32_t arg0) {
// x86-64 prologue: save rbp
switch (arg0) {
case 1000000:
return 5;
case 65536:
return 4;
case 1009:
return 3;
case -1000:
return 1;
case 7:
return 2;
default:
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
// x86-64 epilogue: restore rbp
} gcc -O2
3/3dense_switch pass 11 lines
// glaurung: dense_switch @ 0x1100
int32_t dense_switch(int32_t arg0) {
long ret;
int var0;
ret = 0xffffffff;
if (((unsigned long)((unsigned long)((unsigned int)(arg0))) <= (unsigned long)(7))) {
var0 = (arg0 + 1);
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) + ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) + ((unsigned long)((unsigned int)(var0)) * 4)))) * 2))));
}
return ret;
} hybrid_switch pass 13 lines
// glaurung: hybrid_switch @ 0x1180
int32_t hybrid_switch(int32_t arg0) {
if (((unsigned long)((unsigned int)(arg0)) == 5)) {
return 5;
}
if (((((unsigned long)((unsigned int)(arg0)) == 5) | ((long)(arg0) < 5)) == 0)) {
return (((unsigned long)((unsigned int)(arg0)) == 0xf423f) ? 30 : 0xffffffff);
}
if (((unsigned long)((unsigned int)(arg0)) != 4)) {
return (((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0)) == 0) ? 10 : 0xffffffff);
}
return 25;
} sparse_switch pass 23 lines
// glaurung: sparse_switch @ 0x1120
int32_t sparse_switch(int32_t arg0) {
long ret;
long t33;
long var5;
t33 = ((unsigned long)((unsigned int)(arg0)) - 1009);
if (((unsigned long)((unsigned int)(arg0)) == 1009)) {
return 3;
}
if (((((unsigned long)((unsigned int)(arg0)) == 1009) | ((long)(arg0) < 1009)) == 0)) {
ret = 4;
if (((unsigned long)((unsigned int)(arg0)) == 0x10000)) {
return ret;
}
return (((unsigned long)((unsigned int)(arg0)) == 0xf4240) ? 5 : 0xffffffff);
}
ret = 1;
if (((unsigned long)((unsigned int)(arg0)) == 0xfffffc18)) {
return ret;
}
var5 = ((unsigned long)((unsigned int)(arg0)) == 7);
return (unsigned int)(((var5 + (var5 * 2)) - 1));
}