检查编译器是否将条件提升出循环的最佳方法是在进行全优化编译后检查汇编代码。
使用以下命令构建示例:
g++ -O3 -c example.cpp -o example.o
objdump -d -M intel example.o > example.S
这是我对的结果:
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>
在第三行c处,您会发现正在检查条件:
; if(x != 0)
3c: 85 ff test edi,edi
43: 75 b jne 60 ; ...
从检查点开始,x
将不再被测试,循环只是针对每个部分执行。当x == 0
时,第一个循环从第45行到55行完成。当x != 0
时,第二个循环从第60行到71行完成。
所以,在这种情况下,至少gcc在启用完整优化时能够将条件提升出循环。
x == 0
构建代码。你肯定可以想出编译器无法做到这一点的情况,但在这种情况下,肯定是可以的。[当然,如果您在特定情况下真的很关心,那么请使用您的编译器和实际代码进行基准测试!] - Mats Petersson