> 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.

Reply via email to