This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: target m68k-elf, -m5200, -O2 generates incorrect code for ColdFire


At 15:25 05.07.2002, Peter Jakubek wrote:
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 :-).

I compiled your code with -save-temps -dap -fverbose-asm added and got this in the .s:

moveq.l #1,%d7 | 267 *m68k.md:993/1
add.l %d7,-2(%a6) | i1 | 186 *addsi3_5200/1
move.w -2(%a6),%a0 | i1, i1 | 37 extendhisi2/2
move.l %a0,%a3 | i1, i1 | 234 *m68k.md:993/1

Checking out m68k.md shows that addsi3_5200 calls output_addsi3 in m68k.c. I'm not sure if the bug is there or maybe in reload, cause if you look at the debug RTL dumps you'll notice that the addsi3_5200 first shows up in the .greg dump. Maybe the HImode add shouldn't be converted to a SImode add?

Franz.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]