循环中的常量条件:编译器优化
Constant condition in a loop: compiler optimization
考虑以下代码:
// Preprocessor
#include <iostream>
#include <vector>
// Internal branching
void f1(std::vector<int>& v, const int x = 0)
{
for (unsigned int i = 1; i < v.size(); ++i) {
v[i] = (x != 0) ? (v[i-1]*x) : (v[i-1]+v[i-1]);
}
}
// External branching
void f2(std::vector<int>& v, const int x = 0)
{
if (x != 0) {
for (unsigned int i = 1; i < v.size(); ++i) {
v[i] = v[i-1]*x;
}
} else {
for (unsigned int i = 1; i < v.size(); ++i) {
v[i] = v[i-1]+v[i-1];
}
}
}
// Main
int main()
{
std::vector<int> v(10, 2);
f1(v);
f2(v);
return 0;
}
它说明了产生相同结果的两个函数的行为:
f1
:在回路内部测试条件f2
:在回路外测试条件
分支是基于x
的,CCD_3被声明为const
。
我的问题是:当所有优化级别都打开时,编译器是否足够智能,可以在f2
中转换f1
?
检查编译器是否将条件从循环中提升出来的最佳方法是在使用完全优化编译程序集后真正检查程序集。
在用构建您的示例之后
g++ -O3 -c example.cpp -o example.o
objdump -d -M intel example.o > example.S
以下是我为f1
:获得的内容
00000020 <f1(std::vector<int, std::allocator<int> >&, int)>:
; ...
23: 8b 54 24 10 mov edx,DWORD PTR [esp+0x10]
27: 8b 7c 24 14 mov edi,DWORD PTR [esp+0x14]
2b: 8b 02 mov eax,DWORD PTR [edx]
2d: 8b 4a 04 mov ecx,DWORD PTR [edx+0x4]
30: 29 c1 sub ecx,eax
32: c1 f9 02 sar ecx,0x2
35: 83 f9 01 cmp ecx,0x1
38: 76 d jbe 57 <f1(std::vector<int, std::allocator<int> >&, int)+0x37>
3a: 31 db xor ebx,ebx
3c: 85 ff test edi,edi
3e: ba 01 00 00 00 mov edx,0x1
43: 75 b jne 60 <f1(std::vector<int, std::allocator<int> >&, int)+0x40>
45: 8b 34 18 mov esi,DWORD PTR [eax+ebx*1]
48: 83 c3 04 add ebx,0x4
4b: 01 f6 add esi,esi
4d: 89 34 90 mov DWORD PTR [eax+edx*4],esi
50: 83 c2 01 add edx,0x1
53: 39 d1 cmp ecx,edx
55: 75 ee jne 45 <f1(std::vector<int, std::allocator<int> >&, int)+0x25>
57: 5b pop ebx
58: 5e pop esi
59: 5f pop edi
5a: c3 ret
5b: 90 nop
5c: 8d 74 26 00 lea esi,[esi+eiz*1+0x0]
60: 8b 34 18 mov esi,DWORD PTR [eax+ebx*1]
63: 83 c3 04 add ebx,0x4
66: 0f af f7 imul esi,edi
69: 89 34 90 mov DWORD PTR [eax+edx*4],esi
6c: 83 c2 01 add edx,0x1
6f: 39 ca cmp edx,ecx
71: 75 ed jne 60 <f1(std::vector<int, std::allocator<int> >&, int)+0x40>
73: eb e2 jmp 57 <f1(std::vector<int, std::allocator<int> >&, int)+0x37>
在第3c行,您可以找到正在检查的条件:
; if(x != 0)
3c: 85 ff test edi,edi
43: 75 b jne 60 ; ...
从检查后的那一刻起,x
就再也不会被测试了,只对每个部分执行循环。当CCD_ 9。当CCD_ 10。
因此,是的,至少在这种情况下,gcc能够在启用完全优化的情况下将条件从循环中提升出来。
Godbolt页面告诉我以下内容:
如果循环永远不会进入(size()
<=1),则#6
、#7
立即退出。
#8
、#9
检查x
是否为0,如果为真,则将选择一个循环(.L3
+.L6
),否则将进行第二个循环(CCD _19)。
正如您所看到的,执行了两个优化,包括您查询的那个优化。
相关文章:
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- VS2017调试器:没有地址,可能是由于编译器优化
- 何时允许编译器优化复制构造函数
- 如何使用 GCC 编译器优化创建静态库?
- 为什么 std::chrono 在测量循环和编译器优化的并行 OpenMP 的执行时间时不起作用?
- 是否允许编译器优化掉局部易失性变量
- 删除编译器优化并在发布中启用 pdb 文件
- 静态 constexpr 的编译器优化
- 如何让MSVC编译器优化多步POD初始化?
- 按位不操作的编译器优化
- 模板专用化与编译器优化
- 编译器优化:G 比英特尔慢
- 运算符重载关联性编译器优化
- Intel OpenCL编译器:优化结构使用情况
- C 中编译器优化的影响
- 视觉C++ 2017 错误?编译器优化表达式
- 虚拟功能编译器优化C
- 未定义的行为确实有助于现代编译器优化生成的代码