Wrong code is generated when compiling for
ColdFire with -m5200 -O2.
This is the generated code:
144 0084 7E01 moveq.l #1,%d7
145 0086 DFAE FFFE add.l %d7,-2(%a6)
146 008a 306E FFFE move.w -2(%a6),%a0
A short (16 bit variable) located at -2(%a6) is
incremented by add.l. This can not be correct.
Most of the time correct code like this is generated:
move.w -2(%a6),%a0
addq.l #1,%a0
move.w a0,-2(%a6)
Due to the lack of add.w in the ColdFire architecture
it is required to perform the add in a register.
It seems gcc sometimes does not recognize that the
add must be performed in a register. But gcc still
replaces add.w (not legal for ColdFire) by add.l and
things get messed up.
I could not find what exact condition triggers the
generation of the wrong code demonstrated above. Since
the condition seems to be complex, I provide a very
stripped down version of the file that can reproduce
the problem.
The wrong code sequence is generated to increment the
Loop counter i1 (for loop, i++):
// gcc-3.2-bug-001.cc
//
// Compiled with gcc-3.2 cvs 2002-07-04, configured for --target=m68k-elf
// m68k-elf-gcc.exe -c -m5200 -O2 gcc-3.2-bug.cc
//
typedef unsigned short ushort;
struct struct1 {
char s1_1;
char s1_2;
ushort s1_3;
ushort s1_4;
};
struct1 array1[8][2];
ushort array2[8];
long array3[8][2];
static void foo (void)
{
short i1;
int i2, i3, i4, i5;
unsigned short us6 = 1;
i3 = 0;
for (i1 = 0; i1 < 8; i1++) /* <-- i1 incremented by add.l ! */
{
i2 = 0;
do {
i4 = array1[i1][i2].s1_1;
if ((us6 & 1) != 0) {
array2[i1] &= ~ (1 << i2);
switch (i4) {
case (1) :
i5 = array1[i1][i2].s1_2;
array3[i1][i2] = i5;
break;
default :
i3--;
break;
}
if (++i3 >= 32)
return;
}
i2++;
} while ((us6 >>= 1) != 0);
}
}
Hope someone can help me to correct the problem...
OK, a few hints :-).