C++ 循环中的常量条件:编译器优化

C++ 循环中的常量条件:编译器优化,c++,optimization,c++11,for-loop,conditional,C++,Optimization,C++11,For Loop,Conditional,考虑以下代码: // 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[

考虑以下代码:

// 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(标准::向量&v,常数int x=0)
{
for(无符号整数i=1;i
它说明了产生相同结果的两个函数的行为:

  • f1
    :在循环内部测试条件
  • f2
    :在循环外部测试条件
分支基于
x
,声明为
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>
从这一点开始,在检查之后,
x
将不再进行测试,并且只对每个部分执行循环。从第45行到第55行的第一个循环在
x==0
时完成。当
x!=0

因此,是的,至少在这种情况下,gcc能够在启用完全优化的情况下将条件从循环中提升出来。

告诉我以下几点:


#6
#7
如果无法输入循环,则立即退出(
size()
对于此代码,我希望编译器完全消除检查,只需为
x==0
构建代码。您当然可以想出编译器无法执行此操作的场景,但在这种情况下,当然可以。[当然,如果你真的关心你的特殊情况,那么就用你的编译器和你的真实代码对它进行基准测试!]
  ; if(x != 0)
  3c:   85 ff                   test   edi,edi
  43:   75 b                    jne    60 ; ...