gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > GCC is driving me insane.

#9121 - Domovoi - Mon Jul 28, 2003 6:30 pm

I have a GBA program that compiles just fine. When I insert the following piece of code:

Code:

for (int i=0; i < 5; ++i)
{
    bg2.tileData[32] = 10;
}


...and compile, I get 5 errors:

---

/cygdrive/c/DOCUME~1/Standard/LOCALS~1/Temp/ccepU2IR.s: Assembler messages:
/cygdrive/c/DOCUME~1/Standard/LOCALS~1/Temp/ccepU2IR.s:43: Error: byte or halfword not valid for base register
/cygdrive/c/DOCUME~1/Standard/LOCALS~1/Temp/ccepU2IR.s:44: Error: byte or halfword not valid for base register
/cygdrive/c/DOCUME~1/Standard/LOCALS~1/Temp/ccepU2IR.s:45: Error: byte or halfword not valid for base register
/cygdrive/c/DOCUME~1/Standard/LOCALS~1/Temp/ccepU2IR.s:46: Error: byte or halfword not valid for base register
NMAKE : fatal error U1077: 'gcc' : return code '0x1'

---

Then I change the for statement to this:

Code:

for (int i=0; i < 4; ++i)


...and compile. No problems, compiles just fine.

Since when is it impossible for an int to be a value larger than 3?

It gets weirder. When I change it back to i < 5 and comment out the bg2.tiledata line (which, if you look closely, doesn't even -do- anything with the i variable), it suddenly compiles nicely.

Here's something similar:

This works fine:
Code:

for (int loop=0; loop < 256*32; ++loop)
{
    bg1.tileData[loop] = 0;
}


But this, which is the same code, only twice, generates those five errors again:

Code:

for (int loop=0; loop < 256*32; ++loop)
{
    bg1.tileData[loop] = 0;
}
for (int loop=0; loop < 256*32; ++loop)
{
    bg1.tileData[loop] = 0;
}



And so does this:

for (int loop=0; loop < 256*32; ++loop)
{
bg1.tileData[loop] = 0;
}

for (int loop=0; loop < 256*32; ++loop)
{
bg2.tileData[loop] = 0;
}
[/code]

What's going on here? It's impossible for me to loop through my tile data this way. The compiler seems to just randomly decides when I can and can't use a for loop.

What is this, a plot against me? Is GCC just dodgy? What's going on?

#9123 - Vortex - Mon Jul 28, 2003 7:02 pm

Looks like a data alignment problem. Try to declare your array/structure with 4 byte alignment and compile with no optimization to isolate any optimization problems (-O3 causes problems sometimes).

Also check the size of the structure. You may want to pad to have a size divisible by 4 (i.e. dword aligned).

Examples:
Code:

u16 bg3_buffer[ MAP_WIDTH * MAP_HEIGHT ] __attribute__ ((aligned (4))) = { .... }


struct BGControl
{
   unsigned Priority            : 2;
   unsigned CharacterBaseBlock  : 2;
   unsigned NotUsed             : 2;
   unsigned Mosaic              : 1;
   unsigned ColorPalettes       : 1;
   unsigned ScreenBaseBlock     : 5;
   unsigned DisplayAreaOverflow : 1;
   unsigned ScreenSize          : 2;
} __attribute__ ((aligned (2),packed));

#9129 - Domovoi - Tue Jul 29, 2003 12:20 am

Hmm... Thanks for the reply... Now if only I knew what all that meant. :-)

What is data alignment? Why is GCC having trouble with it? What does 4 byte alignment mean? What does it do? Is there any info I can use to read up on the matter?

Also, about the optimizations... I'm using GCC in VC++6 with a makefile... I guess the optimizations are toggled there?

#9208 - Vortex - Wed Jul 30, 2003 5:53 pm

Domovoi wrote:

What is data alignment? Why is GCC having trouble with it? What does 4 byte alignment mean? What does it do? Is there any info I can use to read up on the matter?


In a nutshell - when the compiler allocates space for your variables (scalars, arrays, structures, etc.) there are two points to consider: starting address and data size. These two aspects depend on the target CPU/architercure - in our case that's ARM, which is a 32-bit processor.
Data alignment is related to how the staring memory address for the variable is assigned. For some oprations (DMA access for example) the staring address should be divisible by 2 (word alignment) or 4 (double word alignment). The same rules apply for the data size of agregate data types (structures/unions). There is an easy way to figure out these two aspects - to see the address of a variable, declare a pointer of that type, assignt it to point to your variable and print pointers value (i.e. the address). Then try to divide that by 4 using a calculator and see if there is any reminder. If there is that means your variable is *not* dword aligned.
To get the size of the variable use the sizeof() operator.

Domovoi wrote:

Also, about the optimizations... I'm using GCC in VC++6 with a makefile... I guess the optimizations are toggled there?


Open your makefile and search for -O2 or -O2. Remove temporary any of these flags. The makefile line usualy looks like CFLAGS= ... -O3. If there is no -O2 or -O3 flag in your current makefile, your problem is not optimization related.

Hope that helps.

#9387 - Domovoi - Sun Aug 03, 2003 8:12 am

Thanks a lot! I had looked around in the makefile before and removed the -O3 bit... Works now. I only wonder... What harmful effect might this have on the code the compiler now generates?

#9390 - tepples - Sun Aug 03, 2003 3:06 pm

-O3 code is generally faster than -O2 code, which is faster than -O code, which is much faster than code without any compiler optimization at all. Try all four options and see which one produces incorrectness.

-O3 produces incorrectness, and -O2 doesn't: The compiler probably has a bug. Here's how to report a bug.

-O or -O2 produces incorrectness, and without optimization doesn't: You likely have a problem in your own code, possibly with respect to pointer aliasing or lack of 'volatile' on a memory-mapped register.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.