In the msgpcc (GCC for MSP430 microcontrollers) manual authors wrote:
Use int instead of char or unsigned char if you want a small integer within a function. The code produced will be more efficient, and in most cases storage isn't actually wasted.
Why int
is more efficient?
UPD. And why (u)int_fast8_t
in the mspgcc defined to (unsigned) char
, not (unsigned) int
. As I understand, (u)int_fast*_t
should be defined to the most efficient type with a suffient size.
In general, not necessarily specific to this processor, it has to do with sign extension and masking, requiring additional instructions to faithfully implement the C source code. A signed 8 bit value in a 16 or 32 or 64 bit processor MAY involve additional instructions to sign extend. An 8 bit add on a 32 bit processor might involve extra instructions to and with 0xFF, etc.
You should do some simple experiments, it took a few iterations but I quickly hit something that showed a difference.
unsigned int fun ( unsigned int a, unsigned int b )
{
return(a+b)<<3;
}
unsigned char bfun ( unsigned char a, unsigned char b )
{
return(a+b)<<3;
}
int sfun ( int a, int b )
{
return(a+b)<<3;
}
char sbfun ( char a, char b )
{
return(a+b)<<3;
}
produces
00000000 <fun>:
0: 0f 5e add r14, r15
2: 0f 5f rla r15
4: 0f 5f rla r15
6: 0f 5f rla r15
8: 30 41 ret
0000000a <bfun>:
a: 4f 5e add.b r14, r15
c: 4f 5f rla.b r15
e: 4f 5f rla.b r15
10: 4f 5f rla.b r15
12: 30 41 ret
00000014 <sfun>:
14: 0f 5e add r14, r15
16: 0f 5f rla r15
18: 0f 5f rla r15
1a: 0f 5f rla r15
1c: 30 41 ret
0000001e <sbfun>:
1e: 8f 11 sxt r15
20: 8e 11 sxt r14
22: 0f 5e add r14, r15
24: 0f 5f rla r15
26: 0f 5f rla r15
28: 0f 5f rla r15
2a: 4f 4f mov.b r15, r15
2c: 30 41 ret
The msp430 has word and byte versions of the instructions so a simple add or subtract doesnt have to do the clipping or sign extension that you would expect when using smaller than register sized variables. As a programmer we might know that we were only going to feed sbfun some very small numbers, but the compiler doesnt and has to faithfully implement our code as written, generating more code between sfun and sbfun. It is not hard to do these experiements with different compilers and processors to see this in action, the only trick is to create code that the processor doesnt have simple instructions to solve.
another example
unsigned int fun ( unsigned int a, unsigned int b )
{
return(a+b)>>1;
}
unsigned char bfun ( unsigned char a, unsigned char b )
{
return(a+b)>>1;
}
produces
00000000 <fun>:
0: 0f 5e add r14, r15
2: 12 c3 clrc
4: 0f 10 rrc r15
6: 30 41 ret
00000008 <bfun>:
8: 4f 4f mov.b r15, r15
a: 4e 4e mov.b r14, r14
c: 0f 5e add r14, r15
e: 0f 11 rra r15
10: 4f 4f mov.b r15, r15
12: 30 41 ret