title: GCC 4.4: Avoid range check on switch/case statement in gcc?
body: <p><a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43462" rel="nofollow noreferrer"><strong>This is only an issue on GCC versions prior to 4.4, this was fixed in GCC 4.5.</strong></a></p>
  
  <p>Is it possible to tell the compiler the variable used in a switch fits within the provided case statements? In particular if it's a small range and there's a jump table generated.</p>
  
  <pre><code>extern int a;
  main()
  {
          switch (a &amp; 0x7) {   // 0x7  == 111  values are 0-7
          case 0: f0(); break;
          case 1: f1(); break;
          case 2: f2(); break;
          case 3: f3(); break;
          case 4: f4(); break;
          case 5: f5(); break;
          case 6: f6(); break;
          case 7: f7(); break;
          }
  }
  </code></pre>
  
  <p>I tried xor'ing to low bits (as the example), using enums, using gcc_unreachable() to no avail. The generated code always checks if the variable is inside the range, adding a pointless branch conditional and moving away the jump table calculation code.</p>
  
  <p>Note: this is in the innermost loop of a decoder, performance matters significantly.</p>
  
  <p>It seems I'm not the <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43462" rel="nofollow noreferrer">only</a> <a href="http://gcc.gnu.org/ml/gcc-help/2008-02/msg00078.html" rel="nofollow noreferrer">one</a>.</p>
  
  <blockquote>
    <p>There is no way to tell gcc that the default branch is never taken,
    although it will omit the default branch if it can prove that the
    value is never out of range based on earlier conditional checks.</p>
  </blockquote>
  
  <p>So, how do you help gcc prove the variable fits and there's no default branch in the example above? (Without adding a conditional branch, of course.)</p>
  
  <h2>Updates</h2>
  
  <ol>
  <li><p>This was on OS X 10.6 Snow Leopard with GCC 4.2 (default from Xcode.) It didn't happen with GCC 4.4/4.3 in linux (reported by Nathon and Jens Gustedt.)</p></li>
  <li><p>The functions in the example are there for readability, think those are inlined or just statements. Making a function call on x86 is expensive.</p>
  
  <p>Also the example, as mentioned in the note, belongs inside a loop on data (big data.)</p>
  
  <p>The generated code with gcc 4.2/OS X is:</p>
  
  <pre><code>[...]
  andl    $7, %eax
  cmpl    $7, %eax
  ja  L11
  mov %eax, %eax
  leaq    L20(%rip), %rdx
  movslq  (%rdx,%rax,4),%rax
  addq    %rdx, %rax
  jmp *%rax
  .align 2,0x90
  L20:
  .long   L12-L20
  .long   L13-L20
  .long   L14-L20
  .long   L15-L20
  .long   L16-L20
  .long   L17-L20
  .long   L18-L20
  .long   L19-L20
  L19:
  [...]
  </code></pre>
  
  <p>The problem lies on <code>cmp $7, %eax;</code> <code>ja L11;</code></p></li>
  <li><p>OK, I'm going with the ugly solution and adding a special case for gcc versions below 4.4 using a different version without a switch and using goto and gcc's &amp;&amp;label extensions.</p>
  
  <pre><code>static void *jtb[] = { &amp;&amp;c_1, &amp;&amp;c_2, &amp;&amp;c_3, &amp;&amp;c_4, &amp;&amp;c_5, &amp;&amp;c_6, &amp;&amp;c_7, &amp;&amp;c_8 };
  [...]
  goto *jtb[a &amp; 0x7];
  [...]
  while(0) {
  c_1:
  // something
  break;
  c_2:
  // something
  break;
  [...]
  }
  </code></pre>
  
  <p>Note the array of labels is static so it's not computed every call.</p></li>
  </ol>