Compilers & Code Generation

loop unrolling

Every trip around a loop has a little tax: increment the counter, test the condition, and jump back to the top. If the actual work in the body is tiny, that tax can be a big fraction of the time. Loop unrolling reduces that tax by doing several iterations' worth of work per trip — copying the body two, four, or eight times and stepping the counter by that many each time, so there are fewer condition-tests and jumps overall.

Concretely, a loop that runs n times with one operation per pass can be rewritten to run n/4 times with four operations per pass. A loop summing an array, for (i = 0; i < n; i++) s += a[i];, becomes (in spirit) a loop that does s += a[i] + a[i+1] + a[i+2] + a[i+3] and advances i by 4, plus a small leftover loop to handle the final 0 to 3 elements when n is not a multiple of 4 (the remainder or epilogue). Beyond cutting loop overhead, unrolling exposes several independent operations side by side, which gives the processor's out-of-order and superscalar machinery more to chew on at once and makes the body easier to vectorize.

It matters because it is a building block for high-performance inner loops and often a prerequisite for good auto-vectorization. But it is governed by a cost model and has real downsides: unrolling makes the code bigger, which can spill out of the instruction cache and actually slow things down, and it only helps when loop overhead is a meaningful share of the work. A caveat worth being honest about: unrolling is not free speed. Compilers unroll selectively at -O2 and -O3, the right factor depends on the chip, and over-unrolling a loop whose body is already heavy gains nothing while bloating the binary — measure before unrolling by hand.

for (i = 0; i < n; i++) s += a[i]; // unrolled by 4 (plus a remainder loop for n not divisible by 4): for (i = 0; i + 3 < n; i += 4) s += a[i] + a[i+1] + a[i+2] + a[i+3]; for (; i < n; i++) s += a[i]; // epilogue handles the leftovers

Four elements per trip cut the loop overhead fourfold; the small epilogue mops up when n is not a multiple of 4.

Unrolling trades code size for fewer loop tests, so it is not unconditionally faster: a bigger body can overflow the instruction cache, and over-unrolling a heavy loop only bloats the binary — let the compiler decide and measure before unrolling by hand.

Also called
unrollingloop unwinding迴圈展開迴圈攤平