> 0000fc40 <main>:
> fc40: 31 40 7e 02 mov #638, r1 ;#0x027e
> fc44: 04 41 mov r1, r4 ;
> fc46: b2 92 00 02 cmp #8, &0x0200 ;r2 As==11
> fc4a: 2a 2c jc $+86 ;abs 0xfca0
> fc4c: 1f 42 00 02 mov &0x0200,r15 ;0x0200
> fc50: 0f 5f rla r15 ;
> fc52: 3f 50 5a fc add #-934, r15 ;#0xfc5a
> fc56: 2f 4f mov @r15, r15 ;
> fc58: 00 4f br r15 ;
> Note that the code is accessing the switch variable twice, in the cmp
> instruction at 0xfc46 and in the mov instruction at 0xfc4c.
That's clearly a bug. I'm trying to figure out how the code gets
generated, but it doesn't seem like a totally canned sequence in one of
the msp430-specific .c or .md files, which would have been an obvious
explanation, as the compiler core wouldn't have known about the two
accesses.
The workaround is obvious: copy to a local variable. But it should be
fixed.
Also, it's pretty crappy code. The right way to do it is to replace
the last three instructions with an ALU op with r0 (PC) as a destination:
fc46: 1f 42 00 02 mov &0x0200,r15
fc4a: 3f 92 cmp #8, r15 ;r2 As==11
fc4c: 2a 29 jc $+80 ;abs 0xfc9a
fc4e: 0f 5f rla r15 ;
fc50: 10 4f 54 fc mov #-940(r15),r0 ;#0xfc54
fc54: <table starts here>
Since you know the value can't be out of range, you can use a GCC
extension to write even more efficient code without range-checking:
int i;
void
dispatch(int iv_value)
{
static void * const vectors[8] = {
&&vec0, &&vec1, &&vec2, &&vec3,
&&vec4, &&vec5, &&vec6, &&vec7 };
goto *(void **)((void *)vectors + iv_value);
do {
vec0:
i = 1; break;
vec1:
i = 2; break;
vec2:
i = 3; break;
vec3:
i = 4; break;
vec4:
i = 5; break;
vec5:
i = 6; break;
vec6:
i = 7; break;
vec7:
i = 8; break;
} while (0);
}
produces (gcc -O -S) almost correct code:
.file "foo.c"
.arch msp430x110
.text
.p2align 1,0
.type vectors.0,@object
.size vectors.0,16
vectors.0:
.short .L2
.short .L3
.short .L4
.short .L5
.short .L6
.short .L7
.short .L8
.short .L9
.p2align 1,0
.global dispatch
.type dispatch,@function
/***********************
* Function `dispatch'
***********************/
dispatch:
/* prologue: frame size = 0 */
.L__FrameSize_dispatch=0x0
.L__FrameOffset_dispatch=0x0
/* prologue end (size=0) */
add #vectors.0, r15
br r15
.L2:
mov #llo(1), &i
ret
.L3:
mov #llo(2), &i
ret
.L4:
mov #llo(3), &i
ret
.L5:
mov #llo(4), &i
ret
.L6:
mov #llo(5), &i
ret
.L7:
mov #llo(6), &i
ret
.L8:
mov #llo(7), &i
ret
.L9:
mov #llo(8), &i
ret
/* epilogue: not required */
/* function dispatch size 31 (31) */
.Lfe1:
.size dispatch,.Lfe1-dispatch
/********* End of function ******/
.comm i,2,2
/*********************************************************************
* File foo.c: code size: 31 words (0x1f)
* incl. words in prologues: 0, epilogues: 0
*********************************************************************/
It's still not doing a direct "mov vectors.0(r15), r0", though.