我如何说服GCC展开一个已知迭代次数但又很大的循环?
我正在编译-O3
.
当然,有问题的真实代码更复杂,但这是一个具有相同行为的简化示例:
int const constants[] = { 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144 }; int get_sum_1() { int total = 0; for (int i = 0; i < CONSTANT_COUNT; ++i) { total += constants[i]; } return total; }
...如果CONSTANT_COUNT
被定义为8(或更少),那么GCC将展开循环,传播常量,并将整个函数简化为简单return
.另一方面,如果CONSTANT_COUNT
是9(或更高),那么循环不会展开,并且GCC会生成一个二进制循环,读取常量,并在运行时添加它们 - 即使理论上,该函数仍然可以被优化到只返回一个常数.(是的,我看过反编译的二进制文件.)
如果我手动展开循环,如下所示:
int get_sum_2() { int total = 0; total += constants[0]; total += constants[1]; total += constants[2]; total += constants[3]; total += constants[4]; total += constants[5]; total += constants[6]; total += constants[7]; total += constants[8]; //total += constants[9]; return total; }
或这个:
#define ADD_CONSTANT(z, v, c) total += constants[v]; int get_sum_2() { int total = 0; BOOST_PP_REPEAT(CONSTANT_COUNT, ADD_CONSTANT, _) return total; }
...然后将函数优化为返回常量.因此,一旦展开,GCC似乎能够处理较大循环的常量传播; 挂起似乎只是让GCC考虑首先展开更长的循环.
但是,既不是手动展开也不BOOST_PP_REPEAT
是可行的选项,因为在某些情况下CONSTANT_COUNT
运行时表达式,并且相同的代码仍然需要在这些情况下正常工作.(在这些情况下,性能不是那么重要.)
我在C(不是C++)工作,所以我也没有模板元编程constexpr
.
我试过-funroll-loops
,-funroll-all-loops
,-fpeel-loops
,和设置较大的值max-unrolled-insns
,max-average-unrolled-insns
,max-unroll-times
,max-peeled-insns
,max-peel-times
,max-completely-peeled-insns
,和max-completely-peel-times
,其中没有一个似乎有所作为.
我在Linux,x86_64上使用GCC 4.8.2.
有任何想法吗?有没有我缺少的旗帜或参数......?