c++循环展开为编译时常数小值
C++ loop unrolling for compile time constant small values
我有这两个函数:
template<int N>
void fun()
{
for(int i = 0; i < N; ++i)
{
std::cout<<i<<" ";
}
}
void gun(int N)
{
for(int i = 0; i < N; ++i)
{
std::cout<<i<<" ";
}
}
我是否可以假设在第一个版本中,编译器将为每个小N(这里的小是指N ={1,2,3,4})优化循环?
我是否可以假设在第一个版本中,编译器将为每个小N优化循环
这是一个典型的优化,尽管"假设"是一个强烈的词。如果一个优化是命令式的,你最终会对任何潜在的优化感到失望。
如果编译器能够内联函数,那么第二个版本可能会经历相同的优化。
您永远无法保证优化将会做什么,但如果给定合适的优化级别,您通常可以依靠它做出比手动优化更好的选择。
如果您真的想知道生成了什么代码,您可以查看一下生成的程序集。
如果编译器可以内联这两个函数中的任何一个,如果它认为这样做是正确的,它也会展开循环。当,编译器如何决定展开一个循环有一个好处是相当复杂的问题,和高度取决于其他因素,如可用寄存器的数量,所发生的内循环(我怀疑上面给出的例子中,例如,将获得多少时间从减少5左右指令参与循环,鉴于cout ...
可能消费几千倍的时间——是否编译器可以算出来是另一回事,但是编译器也不是完全不知道一个函数是否小。
int arr[N]; // Global array.
template<int N>
int fun()
{
int sum = 0;
for(int i = 0; i < N; ++i)
{
sum += arr[i];
}
}
那么我希望编译器展开循环是这样的:
int *tmp = arr;
sum += *tmp++;
sum += *tmp++;
sum += *tmp++;
sum += *tmp++;
sum += *tmp++;
假设N = 5。
这适用于编译器"可见"的任何函数,并且在编译时N是已知的。因此,假设gun
不在不同的源文件中,那么我希望它与fun
(作为模板函数,必须在此编译单元中可见)完全相同地内联和展开
这取决于你的优化级别和标志。-O0 -g
(没有优化,启用调试)、-O3
(积极优化速度)和-Os
(优化空间)之间有很大的区别。
现在循环展开并不一定是一个胜利,即使在优化速度时也是如此。过多的代码可能导致指令缓存丢失,这将大大超过内联简单循环的加速。在这样的循环中,条件分支的成本几乎可以忽略不计,因为分支预测将正确地预测除最后一次迭代之外的所有迭代。
如果你想要更明确一点,你可以使用Duff's Device,它使用切换箱掉入来展开循环。不过,我不能说它在实践中有多好。但是,我可以想象,如果您可以提示编译器展开它,那将会更快。
编译器也很聪明,虽然它们不是绝对正确的,但它们的优化选择通常比我们自己的直觉要好。
- 如何在编译时专门化大型模板函数中的小部分
- 如果我的源文件中使用常数,则如何使编译很好地停止
- 为什么以下C++元编程代码在 N=100 时给出编译错误,但对于小 N 运行良好
- 是否可以将哈希值作为编译时常数
- 结构成员的地址作为编译时间常数之间的差异
- 在VS2017中编译错误C2027,但没有小对象优化
- 重叠小部件的 QT 自定义布局示例无法编译
- 我可以强制C++类使用最小的空间进行编译吗?
- 编译时间评估函数以计算常数
- 错误编译QT创建者 / QT窗口小部件示例
- 用于检查编译时间常数的静态断言未传递给宏
- 关于指针值是编译时常数的困惑
- 将编译的最小C++程序
- 在编译时计算小整数的阶乘
- 定义编译时常数的最佳方式
- 在编译时确定最小公共祖先
- 有什么方法可以用MSVS2015模拟编译时的双常数吗
- 小牛队的 g++ 编译问题
- C++:为什么这个 constexpr 不是编译时常数
- c++循环展开为编译时常数小值