<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<p>Gcc already does use jump tables without the user having to force
anything. Below is a simple C program followed by the X64 assembly
language. Notice the table of addresses and the jump through rax.
But what the programmer has to do is craft their case values to
make a "dense" range that is mostly consecutive. How smart this
is, I don't recall (e.g. if case values 4, 8, 12, 16 would be
recognized as easy to compute an index with, how many "gaps" in
the case value range would be tolerated, etc). But also the
compiler won't use the jump table until there are more than a
handful of cases (the example below, with only three cases
compiled into sequences of tests and conditional branches because
the compiler writer judged the tradeoff of speed and space wasn't
worth it). <br>
</p>
<p>The reason I'm familiar with this is that the gcc compiler's
smarts gave the Linux version of the Java virtual machine an edge
with dispatching op codes but the Sun Solaris C++ compiler didn't
have the optimization (and was in a 'caretaker state' with no hope
of getting the optimization by then, in the early 2000s). But the
speed of dispatch was about interpretation and that was an
absolute nit for code that executed frequently, as it was
automagically compiled into native code by the late 90s and the
quality of that native code got better and better over the years.
<br>
</p>
<p>-Pete</p>
<p><tt>// Just for fun try putting "static" in front of the two int
declarations</tt></p>
<p><tt>// (first mystery _import and then also for
disgusting_global_side effect) and see what comes out with gcc
-S -O4</tt><tt><br>
</tt></p>
<p><tt>int mystery_import;</tt><tt><br>
</tt><tt>int disgusting_global_side_effect;</tt></p>
<p><tt>int main(int argc, char **argv) {</tt><tt><br>
</tt><tt> switch (mystery_import) {</tt><tt><br>
</tt><tt> case 0: </tt><tt><br>
</tt><tt> disgusting_global_side_effect = 123;</tt><tt><br>
</tt><tt> break;</tt><tt><br>
</tt><tt> case 1: </tt><tt><br>
</tt><tt> disgusting_global_side_effect = 124;</tt><tt><br>
</tt><tt> break;</tt><tt><br>
</tt><tt> case 2: </tt><tt><br>
</tt><tt> disgusting_global_side_effect = 125;</tt><tt><br>
</tt><tt> break;</tt><tt><br>
</tt><tt> case 3: </tt><tt><br>
</tt><tt> disgusting_global_side_effect = 126;</tt><tt><br>
</tt><tt> break;</tt><tt><br>
</tt><tt> case 4: </tt><tt><br>
</tt><tt> disgusting_global_side_effect = 127;</tt><tt><br>
</tt><tt> break;</tt><tt><br>
</tt><tt> case 5: </tt><tt><br>
</tt><tt> disgusting_global_side_effect = 128;</tt><tt><br>
</tt><tt> break;</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt> return 0;</tt><tt><br>
</tt><tt>}</tt><tt><br>
</tt><tt><br>
</tt><tt> .file "dense-switch.c"</tt><tt><br>
</tt><tt> .text</tt><tt><br>
</tt><tt> .section .text.startup,"ax",@progbits</tt><tt><br>
</tt><tt> .p2align 4</tt><tt><br>
</tt><tt> .globl main</tt><tt><br>
</tt><tt> .type main, @function</tt><tt><br>
</tt><tt>main:</tt><tt><br>
</tt><tt>.LFB0:</tt><tt><br>
</tt><tt> .cfi_startproc</tt><tt><br>
</tt><tt> endbr64</tt><tt><br>
</tt><tt> cmpl $5, mystery_import(%rip)</tt><tt><br>
</tt><tt> ja .L2</tt><tt><br>
</tt><tt> movl mystery_import(%rip), %eax</tt><tt><br>
</tt><tt> leaq .L4(%rip), %rdx</tt><tt><br>
</tt><tt> movslq (%rdx,%rax,4), %rax</tt><tt><br>
</tt><tt> addq %rdx, %rax</tt><tt><br>
</tt><tt> notrack jmp *%rax</tt><tt><br>
</tt><tt> .section .rodata</tt><tt><br>
</tt><tt> .align 4</tt><tt><br>
</tt><tt> .align 4</tt><tt><br>
</tt><tt>.L4:</tt><tt><br>
</tt><tt> .long .L9-.L4</tt><tt><br>
</tt><tt> .long .L8-.L4</tt><tt><br>
</tt><tt> .long .L7-.L4</tt><tt><br>
</tt><tt> .long .L6-.L4</tt><tt><br>
</tt><tt> .long .L5-.L4</tt><tt><br>
</tt><tt> .long .L3-.L4</tt><tt><br>
</tt><tt> .section .text.startup</tt><tt><br>
</tt><tt>.L3:</tt><tt><br>
</tt><tt> movl $128, disgusting_global_side_effect(%rip)</tt><tt><br>
</tt><tt>.L2:</tt><tt><br>
</tt><tt> xorl %eax, %eax</tt><tt><br>
</tt><tt> ret</tt><tt><br>
</tt><tt>.L5:</tt><tt><br>
</tt><tt> movl $127, disgusting_global_side_effect(%rip)</tt><tt><br>
</tt><tt> jmp .L2</tt><tt><br>
</tt><tt> movl $123, disgusting_global_side_effect(%rip)</tt><tt><br>
</tt><tt> jmp .L2</tt><tt><br>
</tt><tt>.L8:</tt><tt><br>
</tt><tt> movl $124, disgusting_global_side_effect(%rip)</tt><tt><br>
</tt><tt> jmp .L2</tt><tt><br>
</tt><tt>.L7:</tt><tt><br>
</tt><tt> movl $125, disgusting_global_side_effect(%rip)</tt><tt><br>
</tt><tt> jmp .L2</tt><tt><br>
</tt><tt>.L6:</tt><tt><br>
</tt><tt> movl $126, disgusting_global_side_effect(%rip)</tt><tt><br>
</tt><tt> jmp .L2</tt><tt><br>
</tt><tt> .cfi_endproc</tt><tt><br>
</tt><tt>.LFE0:</tt><tt><br>
</tt><tt> .size main, .-main</tt><tt><br>
</tt><tt> .comm disgusting_global_side_effect,4,4</tt><tt><br>
</tt><tt> .comm mystery_import,4,4</tt><tt><br>
</tt><tt> .ident "GCC: (Ubuntu 9.3.0-10ubuntu2) 9.3.0"</tt><tt><br>
</tt><tt> .section .note.GNU-stack,"",@progbits</tt><tt><br>
</tt><tt> .section .note.gnu.property,"a"</tt><tt><br>
</tt><tt> .align 8</tt><tt><br>
</tt><tt> .long 1f - 0f</tt><tt><br>
</tt><tt> .long 4f - 1f</tt><tt><br>
</tt><tt> .long 5</tt><tt><br>
</tt><tt>0:</tt><tt><br>
</tt><tt> .string "GNU"</tt><tt><br>
</tt><tt>1:</tt><tt><br>
</tt><tt> .align 8</tt><tt><br>
</tt><tt> .long 0xc0000002</tt><tt><br>
</tt><tt> .long 3f - 2f</tt><tt><br>
</tt><tt>2:</tt><tt><br>
</tt><tt> .long 0x3</tt><tt><br>
</tt><tt>3:</tt><tt><br>
</tt><tt> .align 8</tt><tt><br>
</tt><tt>4:</tt><br>
<br>
</p>
<p><br>
</p>
<div class="moz-cite-prefix">On 7/1/20 2:12 PM, Jon Wolfe via
TriEmbed wrote:<br>
</div>
<blockquote type="cite" cite="mid:md5:QV09Nx1XOt%2FMpYir+IKsYw==">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Generator" content="Microsoft Word 15 (filtered
medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
.MsoChpDefault
{mso-style-type:export-only;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style>
<div class="WordSection1">
<p class="MsoNormal">This is one of those rare circumstances,
imho, where goto can reasonably be used, Dijkstra be damned <span
style="font-family:"Segoe UI Emoji",sans-serif">😊</span>.
</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Where I have seen it used like this , it’s
an optimization, and doesn’t change the semantics of code flow
from a traditional switch-case, and it was wrapped in a macro
I think so it could be used, if supported, by the compiler.
It’s like putting inline assembly in the code: only do it if
the benefit is worth the sacrifice in code portability and
maintainability. </p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I’m not a compiler optimization expert, but
the code generation optimization of using a jump table would
be at the discretion of the optimizer, using a goto construct
would be a way to force that. It may also be the case that the
way it is implemented at the machine code level is faster
using gotos. </p>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</blockquote>
</body>
</html>