循环展开(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];
}
}
为什么要这样做?
循环展开对于编译器优化非常有意义,如果循环体中的操作有些可以消除冗余,可以被矢量化,或者可以被其他优化技术处理,那么循环展开可以通过增加代码长度,来间接增加编译器的优化空间。例如,下面这个循环:
展开后可以发现,这里有冗余的操作,可以被编译器优化掉: