#152569 - no2pencil - Mon Mar 17, 2008 9:25 pm
I see that most code examples use u16 when defining variables of type int, however for functions that define them as int. In the past I have defined variables of type int, just from force of habit, & I have not gotten an error & the code compiles.
Is there a reason for defining variables as type u16/u8? Do you get any performance difference?
_________________
-#2pencil
#152573 - gauauu - Mon Mar 17, 2008 9:38 pm
If for some reason, you really need to specify a number of bits for the type you are using, it's ok to use u16. (Like if you are reading/writing 16-bit registers).
For general use of when you need an integer value, it is best to use int. On the gba, this will be a 32-bit integer, which, based on the architecture, is faster than using 16-bit integers.
#152590 - Cearn - Tue Mar 18, 2008 12:38 am
no2pencil wrote: |
Is there a reason for defining variables as type u16/u8? Do you get any performance difference? |
Yes, there is a performance difference. Because the CPU uses 32-bit registers, extra instructions have to be added after arithmetic to keep the values within 8 or 16 bits. For example, this code:
Code: |
u16 sum(u16 array[], u16 size)
{
u16 i, sum=0;
for(i=0; i<size; i++)
sum += array[i];
return sum;
} |
will actually be compiled more like this:
Code: |
u16 sum(u16 array[], u16 size)
{
u16 i, sum=0;
for(i=0; i<size; )
{
sum += array[i];
sum <<= 16; // -- restrict to 16 bits
sum >>= 16; // /
i++;
i <<= 16; // -- restrict to 16 bits
i >>= 16; // /
}
return sum;
} |
The two extra shift-pairs are required because i and sum are 16-bit; if they'd been 32-bit, the shifts wouldn't be there. Basically, the loop has doubled in size purely because of the use of non-32-bit datatypes. Depending on the specifics of the code, the difference in speed can be quite high.
Note that this only really applies for local variables; for memory-based variables (structs, arrays, globals), the case can be a little different. As a basic rule, variables should be 32-bits unless there's a really good reason for them to be something else. For another example and a slightly longer explanation, go here.
#152596 - Dwedit - Tue Mar 18, 2008 1:48 am
On the other hand, when you need a constant table of values (bounded between 0-65535), or need a medium to large-size array with that range, use u16 for the array, then use ints to when you read or write to the array.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."
#152648 - gmiller - Tue Mar 18, 2008 9:56 pm
The load and store instruction handle the conversion from 16 to 32 and 32 to 16 as part of the instruction so for load and stores it makes little difference. But for computation the registers are 32 bit only so doing math in anything other than 32 bits causes the compiler to use extra bit limiting instructions as Cearn pointed out.
Since the CPU here is a RISC processor the only thing you can do to main memory is load and store. Any computation has to be done in a register so using 32 bit values is desirable. There are a number of other things that can influence the compiler to output better code as well. Of course the compiler is not perfect and it's approach is do no harm so the conservative way it does things can produce code that is not the best for performance.
#152651 - Dwedit - Tue Mar 18, 2008 11:32 pm
I think ARM completely dropped the ball when they failed to include a "load and set flags" instruction. I always end up doing something like this:
ldrb r0,something
movs r0,r0
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."