Tip #10 Unrolling Loops

In some cases, we could unroll loops to speed up the code execution. This is especially effective for short loops. After a loop is unrolled, there are no loop indices to be tested and fewer branches are executed each round in the loop.

The table below shows the effect of unrolling loops.

Table 1. Example of Unrolling Loops
Loops Unrolling loops
C source code
#include <avr/io.h>
int main(void)
{
uint8_t loop_cnt = 10;
do {
PORTB ^= 0x01;
 } while (--loop_cnt);
}
#include <avr/io.h>
int main(void)
{
 PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
PORTB ^= 0x01;
}
AVR Memory Usage

Program: 94 bytes (1.5% Full)

(.text + .data + .bootloader)

Data: 0 bytes (0.1% Full)

(.data + .bss + .noinit)

Program: 142 bytes (1.7% Full)

(.text + .data + .bootloader)

Data: 0 bytes (0.0% Full)

(.data + .bss + .noinit)

Cycle counter 80 50
Compiler optimization level -O2 -O2

By unrolling the "do { } while ( )" loop, we significantly speed up the code execution from 80 clock cycles to 50 clock cycles.

Be aware that the code size is increased from 94 bytes to 142 bytes after unrolling the loop. This is also an example to show the tradeoff between speed and size optimization.

Note: If -O3 option is enabled in this example, the compiler will unroll the loop automatically and generate the same code as unrolling loop manually.