In some cases GCC generates very large jump tables, e.g. the table can contain too few different case values wrt. the table size. In these cases when optimizing for size it would be preferable to use some other mechanism for the jumping problem. For example, in some cases it would be more effecient to create simple compare and branch pairs for checking the case values. --- c example --- // arm-elf-gcc -S -g0 -Os -o large-jump.s large-jump.c int i; int func(int a) { switch(a) { case 0: i = 20; break; case 1: i = 50; break; case 2: i = 29; break; case 10: i = 20; break; case 11: i = 50; break; case 12: i = 29; break; case 20: i = 20; break; case 21: i = 50; break; case 22: i = 29; break; case 52: i = 79; break; case 110: i = 27; break; default: i = 77; break; } return i; } --- arm code --- func: ldr r2, .L17 cmp r0, #110 ldrls pc, [pc, r0, asl #2] b .L14 .p2align 2 .L15: .word .L9 .word .L10 .word .L11 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L9 .word .L10 .word .L11 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L9 .word .L10 .word .L11 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L12 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L14 .word .L13 .L9: mov r3, #20 b .L16 .L10: mov r3, #50 b .L16 .L11: mov r3, #29 b .L16 .L12: mov r3, #79 b .L16 .L13: mov r3, #27 b .L16 .L14: mov r3, #77 .L16: str r3, [r2, #0] ldr r3, .L17 ldr r0, [r3, #0] mov pc, lr
I agruee with this and maybe this one can be done with GCC's current infrostructor but who knows.
You should look at stmt.c:expand_end_case_type(), under the comment: /* If range of values is much bigger than number of values, make a sequence of conditional branches instead of a dispatch. If the switch-index is a constant, do it this way because we can optimize it. */ The heuristic following this comment now does: || compare_tree_int (range, 10 * count) > 0 where "count" is the number of case labels, and range is the range of the case labels. In your example, count==11, and range==110, so you just hit the case where it still gets expanded with a jump table. (I suppose you knew this, judging from your example ;-) So why not replace this heuristic with something like: || compare_tree_int (range, (optimize_size ? 3 : 10) * count) > 0 and see if it helps...
The problem has been fixed. See the following mail and cvs diff. http://gcc.gnu.org/ml/gcc-patches/2003-08/msg02054.html http://sources.redhat.com/cgi-bin/cvsweb.cgi/gcc/gcc/stmt.c.diff?r1=1.326&r2=1.327&cvsroot=gcc