Small Integers: Big Penalty
10/06/2012
When writing C code for 32-bit or 64-bit execution, what is the best choice of integer size for generic local variables? Factors to consider include runtime performance and code size. Using int or unsigned int to select default sized integers is recognized as optimum for runtime performance. For example, AMD's Software Optimization Guide for AMD Family 15h Processors states: Use 32-bit integers instead of smaller sized integers (16-bit or 8-bit). Note that int selects a 32-bit integer for both the x86 and x64 environments supported by AMD processors. But what integer type is best when minimum code size is important, such as in BIOS or other embedded code? Inspection of open source BIOS code from projects such as coreboot and UEFI suggests 8 or 16 bit integers might lead to the smallest code size. Here is an example from the AMD DDR3 reference code portion of the coreboot project. The function calculates the DDR3 DIMM SPD CRC:
BOOLEAN
STATIC
MemTCRCCheck3 (
IN OUT UINT8 *SPDPtr
)
{
UINT16 Crc;
INT16 i;
INT16 j;
INT16 Count;
if (SPDPtr[SPD_TYPE] == JED_DDR3SDRAM) {
Count = (SPDPtr[SPD_BYTE_USED] & 0x80) ? 117 : 126;
Crc = 0;
for (j = 0; j < Count; j++) {
Crc = Crc ^ ((UINT16)SPDPtr[j] << 8);
for (i = 0; i < 8; i++) {
if (Crc & 0x8000) {
Crc = (Crc << 1) ^ 0x1021;
} else {
Crc = (Crc << 1);
}
}
}
if (*(UINT16 *) (SPDPtr + 126) == Crc) {
return TRUE;
}
}
The five occurrences of 16-bit integer usage marked in red can be replaced with 32-bit integers without affecting operation of the function's main loop (the final Crc must be truncated to 16 bits). The code can be compiled and benchmarked in original and 32-bit form. Results:
Original (16-bit integers) Modified (32-bit integers)
Compiler bytes cycles bytes cycles
Microsoft 120 9571 92 6268
VS2008 32-bit
Microsoft 115 6403 100 4390
VS2008 64-bit
gcc 4.72 85 5092 82 4127
x86 32-bit
gcc 4.72 84 4127 81 4229
x86 64-bit
gcc 4.71 125 not tested 113 not tested
arm 32-bit
Replacing 16-bit integers with
32-bit integers reduced code size in all 5 cases. Use of default size
integers results in code that is not only faster, but smaller too. A side
benefit of using default size for integer variables is reduced concern with integer overflow.
The files used to create this table are here. The arm compiler is from here and the x86 gcc compilers are from here. Cycle counts were measured on the Intel i7-2600K processor.