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.