【问题标题】:Constant condition in a loop: compiler optimization [duplicate]循环中的常量条件:编译器优化
【发布时间】:2013-08-15 16:11:18
【问题描述】:

考虑以下代码:

// 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,声明为const

我的问题是:当所有优化级别都打开时,编译器是否足够智能以将f1 转换为f2

【问题讨论】:

  • 对于这段代码,我希望编译器完全消除检查,只为x == 0 构建代码。您当然可以提出编译器无法做到这一点的场景,但在这种情况下,当然可以。 [当然,如果你真的关心你的特殊情况,那么用你的编译器和你的真实代码对它进行基准测试!]

标签: c++ optimization c++11 for-loop conditional


【解决方案1】:

Godbolt page 告诉我以下事情:

#6,#7 如果永远不会进入循环,则立即退出 (size()

#8,#9 检查x是否不为0,如果为真,则选择一个循环(.L3 + .L6),否则将进行第二个循环(.L5) .

如您所见,执行了两项优化,包括您查询的一项。

【讨论】:

    【解决方案2】:

    检查您的编译器是否将条件提升到循环之外的最佳方法是在使用完全优化编译后真正检查程序集。

    在构建您的示例之后:

    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 将不再被测试,循环只是为每个部分执行。从第 45 行到第 55 行开始的第一个循环在 x == 0 时完成。从第 60 行到第 71 行的第二个循环在 x != 0 时完成。

    所以是的,至少在这种情况下,gcc 能够在启用完全优化的情况下将条件提升到循环之外。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-11
      • 1970-01-01
      • 2012-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-04
      相关资源
      最近更新 更多