跳至主要內容

循环展开(Loop Unrolling)

西风逍遥游大约 1 分钟

循环展开(Loop Unrolling)

循环展开(Loop Unrolling)是一种优化技术,它通过减少循环的迭代次数来减少循环的开销。循环展开的基本思想是将循环体中的多次迭代合并为一次迭代,从而减少循环的迭代次数。循环展开的优点是可以减少循环的开销,缺点是会增加代码的长度,可能会增加缓存的失效率。

一个直观的例子

假设有如下的循环:

void add(float *a, float *b, float *c, int n) {
  for (int i = 0; i < n; i++) {
    c[i] = a[i] + b[i];
  }
}

我们可以将这个循环展开为:

void add(float *a, float *b, float *c, int n) {
  for (int i = 0; i < n; i+=2) {
    c[i] = a[i] + b[i];
    c[i+1] = a[i+1] + b[i+1];
  }
}

这样,每次迭代处理两个元素,减少了循环的迭代次数。但如果n不能被2整除,我们需要在循环的最后处理剩余的元素:

void add(float *a, float *b, float *c, int n) {
  for (int i = 0; i < n; i+=2) {
    c[i] = a[i] + b[i];
    c[i+1] = a[i+1] + b[i+1];
  }
  for (int i = n-n%2; i < n; i++) {
    c[i] = a[i] + b[i];
  }
}

为什么要这样做?

循环展开对于编译器优化非常有意义,如果循环体中的操作有些可以消除冗余,可以被矢量化,或者可以被其他优化技术处理,那么循环展开可以通过增加代码长度,来间接增加编译器的优化空间。例如,下面这个循环:

展开后可以发现,这里有冗余的操作,可以被编译器优化掉: