5

Suppose I have N different integral values known at compile time, V_1 through V_N. Consider the following structures:

const int x = foo();
switch(x) {
case V_1: { /* commands for V_1 which don't change x */ } break;
case V_2: { /* commands for V_1 which don't change x */ } break;
/* ... */
case V_N: { /* commands for V_1 which don't change x */ } break;
}

versus

const int x = foo();
if      (x == V_1) { /* commands for V_1 which don't change x */ }
else if (x == V_2) { /* commands for V_2 which don't change x */ }
else ...
else if (x == V_N) { /* commands for V_N which don't change x */ }

Do modern C++ compilers treat these differently? That is, do they apply different potential optimization to these code structures? Or do they "canonicalize" them to the same for, then decide on optimizations (such as whether to form a jump table or not)?

Notes:

  • By modern C++ compilers I mean mostly recent versions of GCC, clang and MSVC. ICC could also be relevant.
  • Please answer regarding the maximum optimization level (-O3 for clang and GCC)
  • ... but then, if the treatment of switches and if-then-else-chains is the same in some optimization levels and different in others, that's also interesting.
  • I'm guessing the answer might depend on the value of N - give thresholds if possible.
einpoklum
  • 118,144
  • 57
  • 340
  • 684

1 Answers1

4

Ironically, that is exactly the test I did just a couple of days back for most recent compilers. As it happened, with latest compilers, clang produces the same assembly for switch and if - for small number of cases (below 5) it produces a bunch of direct conditional jumps, while for 5 or more cases it does an indirect table jump.

On the other hand, gcc treats those differently: it converts switch to indirect table jump, while a series of if statements remain a series of conditional direct jumps.

It is also worth noting, that if switch case has "holes" in it (i.e. possible values for control variable which are not covered by case label), it can be still converted into series of conditional direct jumps or indirect table jump, but I wasn't able to figure out the exact formula.

Here is some play code: https://gcc.godbolt.org/z/Lll1Kd

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • I was interested more in how the compilers approached this rather than whether finally the resulting code was the same, but I'll read the link. – einpoklum Nov 07 '18 at 21:55
  • 1
    @einpoklum I am not sure what you mean by 'how compilers approaching it'. Isn't the resulting code the best judge? – SergeyA Nov 07 '18 at 21:57
  • The same results could be accidental rather than fundamental. Anyway, suggest you change your link to [this](https://gcc.godbolt.org/z/Wx9WOR): Less `boo()'`ing, and easier to compare the resulting assemby. – einpoklum Nov 07 '18 at 22:07
  • I've just filed a bug against GCC on this issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87925 – einpoklum Nov 07 '18 at 22:24
  • @einpoklum interesting what will happen out of it. I'd love to see series of if having the same treatment as case labels. – SergeyA Nov 08 '18 at 15:12