Forth like interpreter
Kragen Sitaker
kragen at dnaco.net
Tue Mar 14 10:01:07 EST 2000
In article <8al719$h5c$1 at nnrp1.deja.com>, <fredrik at pythonware.com> wrote:
>> Not all compilers implement switch statements as jump-tables.
>
>really? can you name one that doesn't?
gcc 2.95.2 doesn't always implement switch statements as jump-tables
when compiling for i386. Sometimes it implements them with a rat's
nest of jumps. Here are two examples, one where it uses a jump-table
and one where it doesn't.
nclude <stdio.h>
int main(int argc, char **argv) {
switch(argc) {
case 1:
printf("got a unity\n");
return 0;
case 2: case 3:
printf("got two or three\n");
return 1;
case 4:
printf("got four, a square!\n");
return 2;
case 5:
printf("got five\n");
return 1;
case 6:
printf("got the first perfect number\n");
return 2;
case 7:
printf("got seven\n");
return 1;
default:
printf("got something weird\n");
return -1;
}
}
This switch compiles to a jump table. Here's the output of gcc -Wall
-S; the jump table is at .L12. -O2 leaves it as a jump table.
.file "switch2.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "got a unity\n"
.LC1:
.string "got two or three\n"
.LC2:
.string "got four, a square!\n"
.LC3:
.string "got five\n"
.LC4:
.string "got the first perfect number\n"
.LC5:
.string "got seven\n"
.LC6:
.string "got something weird\n"
.text
.align 4
.globl main
.type main, at function
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl 8(%ebp),%eax
decl %eax
cmpl $6,%eax
ja .L11
movl .L12(,%eax,4),%eax
jmp *%eax
.p2align 4,,7
.section .rodata
.align 4
.align 4
.L12:
.long .L4
.long .L6
.long .L6
.long .L7
.long .L8
.long .L9
.long .L10
.text
.p2align 4,,7
.L4:
addl $-12,%esp
pushl $.LC0
call printf
addl $16,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L5:
.L6:
addl $-12,%esp
pushl $.LC1
call printf
addl $16,%esp
movl $1,%eax
jmp .L2
.p2align 4,,7
.L7:
addl $-12,%esp
pushl $.LC2
call printf
addl $16,%esp
movl $2,%eax
jmp .L2
.p2align 4,,7
.L8:
addl $-12,%esp
pushl $.LC3
call printf
addl $16,%esp
movl $1,%eax
jmp .L2
.p2align 4,,7
.L9:
addl $-12,%esp
pushl $.LC4
call printf
addl $16,%esp
movl $2,%eax
jmp .L2
.p2align 4,,7
.L10:
addl $-12,%esp
pushl $.LC5
call printf
addl $16,%esp
movl $1,%eax
jmp .L2
.p2align 4,,7
.L11:
addl $-12,%esp
pushl $.LC6
call printf
addl $16,%esp
movl $-1,%eax
jmp .L2
.p2align 4,,7
.L3:
.L2:
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 2.95.2 20000220 (Debian GNU/Linux)"
This switch, on the other hand, compiles to an altogether different
sort of structure:
#include <stdio.h>
int main(int argc, char **argv) {
switch (argv[0][0]) {
case 'a':
return 73;
case 'Q':
return 81;
case '!':
return 33;
case '-':
printf("%s [aQ!]\n", argv[0]);
return 0;
default:
return 1;
}
}
Here's what it compiles to, with some comments I added:
.file "switch.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "%s [aQ!]\n"
.text
.align 4
.globl main
.type main, at function
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl 12(%ebp),%eax
movl (%eax),%edx
movb (%edx),%al ; load argv[0][0]
cmpb $81,%al
je .L5 ; if 'Q', go to .L5
cmpb $81,%al
jg .L10 ; if not above 'Q':
cmpb $33,%al
je .L6 ; if '!', go to .L6
cmpb $45,%al
je .L7 ; if '-', go to .L7
jmp .L8 ; otherwise, go to .L8 ("default:")
.p2align 4,,7
.L10: ; else (below 'Q'):
cmpb $97,%al
je .L4 ; if 'a', go to .L4
jmp .L8 ; otherwise, go to .L8 ("default:")
.p2align 4,,7
.L4:
movl $73,%eax
jmp .L2
.p2align 4,,7
.L5:
movl $81,%eax ; when I wrote this code, I honestly didn't
; realize 81 was the ASCII code for 'Q'. I guess
; I have ASCII on the brain.
jmp .L2
.p2align 4,,7
.L6:
movl $33,%eax ; I *did* know '!' was 33, though.
jmp .L2
.p2align 4,,7
.L7:
addl $-8,%esp
movl 12(%ebp),%eax
movl (%eax),%edx
pushl %edx
pushl $.LC0
call printf
addl $16,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L8:
movl $1,%eax
jmp .L2
.p2align 4,,7
.L3:
.L2:
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 2.95.2 20000220 (Debian GNU/Linux)"
-O2 swizzles some blocks around and eliminates some useless
instructions, but leaves the rat's-nest.
The polymorphic inline cache people seem to think that a couple of
tests might be quicker than a jump table in many cases these days.
--
<kragen at pobox.com> Kragen Sitaker <http://www.pobox.com/~kragen/>
The Internet stock bubble didn't burst on 1999-11-08. Hurrah!
<URL:http://www.pobox.com/~kragen/bubble.html>
The power didn't go out on 2000-01-01 either. :)
More information about the Python-list
mailing list