CW7 for CF switch/case optimized code generation bug?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

CW7 for CF switch/case optimized code generation bug?

2,151 Views
RichTestardi
Senior Contributor II
Hi,
 
I am seeing what appears to be a code generation bug when I turn up optimization (from level 1 to level 2) on a switch/case statement.  The compiler is generating a jump table in the code segment, and the destination of the jump table skips (at least) one instruction critical to the case statement.
 
The switch statement looks like:
 
    switch (code) {
00007580: 122EFF65        move.b   -155(a6),d1
00007584: 7000            moveq    #0,d0
00007586: 1001            move.b   d1,d0
00007588: 0C800000009C    cmpi.l   #156,d0
0000758E: 6E000B5E        bgt.w    run_bytecode+0xc12 (0x80ee); 0x000080ee
00007592: 0C8000000080    cmpi.l   #128,d0
00007598: 6D000B54        blt.w    run_bytecode+0xc12 (0x80ee); 0x000080ee
0000759C: 048000000080    subi.l   #128,d0
000075A2: 303B0A08        move.w   (8,pc,d0.l*2),d0
000075A6: 48C0            ext.l    d0
000075A8: 4EFB0A00        jmp      (pc,d0.l*2)
 
The jump table that follows is:
 
000075AC:
  05A3  001E  0023  05A2 
  05A2  006F  05A2  05A2 
  05A2  05A2  05A2  01B6 
  0228  05A2  05A2    02CA 
  034E  03CE  0401  042E 
  04B3  05A2  05A2  050D 
  0541  0567  0567  04F3 
  0500  2D6E
 
I am taking the entry at offset 5 ("code" is 0x85 and the case density space begins at 0x80) -- which is 006f, leading to a branch destination of 0x7688.
 
The problem is that 0x7688 is what appears to be three instructions into my case (which should begin at 0x767C):
 
        case code_dim:
0000767C: 282E0010        move.l   16(a6),d4
00007680: 7A01            moveq    #1,d5
                    var_type = code_ram;
00007682: 263C00000087    move.l   #135,d3
00007688: 2007            move.l   d7,d0
0000768A: D086            add.l    d6,d0
...
 
I understand that with optimized code, the disassembly and source don't always align exactly; however, the "move.l   #135,d3" is never executed, and that is passed as an argument into an underlying function that asserts it is passed correctly, so it is a required part of the case.
 
Can anyone suggest what I can do to work around this, or should I just not use the optimizer?
 
I have verified that at level 1 optimization the jump table (which is still used) is correct.
 
Thanks.
 
-- Rich
 
Labels (1)
0 Kudos
4 Replies

484 Views
RichTestardi
Senior Contributor II
It turns out that the following construct can cause the compiler to generate bad code (skipping portions of case 3)  at optimization levels 2 and above:
 
  switch (x) {
    case 1:
      break;
    case 2:
      break;
    case 3:
      do {
        ...
      } while (...);
      break;
    case 4:
      break;
    case 5:
      break;
  }
 
It looks like the key ingredient is the do...while loop as the first code in the case statement -- adding a global variable increment before the do...while loop fixed everything.
 
The bug did seem to require at least two preceding cases and two following ones, but I'll work on a minimal test program to isolate this next week, and will post it here.
 
-- Rich
0 Kudos

484 Views
CrasyCat
Specialist III
Hello
 
I would recommend you to submit a service request for that in order to get our engineering team to fix the issue.

Click here to submit a service request.

Make sure to attach a reproducible project and installed product information to the service request.
To generate the required information:
- Start CodeWarrior
- Open the project
- Select "Help" -> "Pack and Go" and follow instructions on the screen.

Attach the generated .zip file to the SR.
 
CrasyCat
0 Kudos

484 Views
RichTestardi
Senior Contributor II
Just for grins, I created a minimal program to demonstrate this bug -- it works at level 1 optimization and fails at level 4 with a blown assert in verify(), and single-stepping reveals the initial statements in case 3 are skipped.  I'll submit it as a service request now.
 
Code:
/* * main implementation: use this sample to create your own application * */#include "support_common.h" /* include peripheral declarations and more */#if (CONSOLE_IO_SUPPORT || ENABLE_UART_SUPPORT) /* Standard IO is only possible if Console or UART support is enabled. */#include <stdio.h>#endif#define assert(x)  if (! (x)) { asm { halt } }#define SMALLCODE(v) (v++, v *= 2, v--)#define MEDIUMCODE  SMALLCODE(a)+SMALLCODE(b)-SMALLCODE(c)+SMALLCODE(d)#define LARGECODE  a=MEDIUMCODE; b=MEDIUMCODE; c=MEDIUMCODE; d=MEDIUMCODE;static volatile int g;static volatile int a;static volatile int b;static volatile int c;static volatile int d;static volatile int xx;static volatile int yy;static volatile int zz;static void verify(int x, int y, int z){    assert(x == 123);    assert(xx == 123);    assert(y == 234);    assert(yy == 234);    assert(z == 345);    assert(zz == 345);}int main(void){    int q;    int x;    int y;    int z;    #if (CONSOLE_IO_SUPPORT || ENABLE_UART_SUPPORT)  printf("Hello World in C from MCF52221 derivative on MCF52221 board\n\r"); fflush(stdout);#endif    g = 3;    q = 0;        switch (g) {        case 1:            LARGECODE            break;        case 2:            LARGECODE            break;        case 3:            do {                x = 123;                xx = x;                y = 234;                yy = y;                z = 345;                zz = z;                LARGECODE                verify(x, y, z);                x = 0;                xx = x;                y = 0;                yy = y;                z = 0;                zz = z;            } while (q++<10);            break;        case 4:            LARGECODE            break;        case 5:            LARGECODE            break;    }        printf("OK!\n\r");    while (1) {        g++;    }}

 
0 Kudos

484 Views
RichTestardi
Senior Contributor II
And since I can't seem to get the attachments into the service request, I'm (hopefully!) attaching them here. :smileysad:
0 Kudos