Mar*_*son 9 c++ optimization gcc clang++
下面声明norm的C++ vector类中的成员函数标记为const和(据我所知)不包含任何副作用.
template <unsigned int N>
struct vector {
  double v[N];
  double norm() const {
    double ret = 0;
    for (int i=0; i<N; ++i) {
      ret += v[i]*v[i];
    }
    return ret;
  }
};
double test(const vector<100>& x) {
  return x.norm() + x.norm();
}
如果我打电话norm多次上const的实例vector(见test上面的函数)与GCC编译器(5.4版本)和优化开启(即-O3),那么编译器内联norm,但仍计算的结果norm多次,即使结果不应该改变.为什么编译器不优化第二次调用norm而只计算一次这个结果?这个答案似乎表明,如果编译器确定该norm函数没有任何副作用,编译器应该执行此优化.为什么在这种情况下不会发生这种情况?
请注意,我正在使用Compiler Explorer确定编译器生成的内容,并且下面给出了gcc版本5.4的程序集输出.clang编译器给出了类似的结果.另请注意,如果我使用gcc的编译器属性手动标记norm为使用const函数__attribute__((const)),那么第二次调用会根据需要进行优化,但我的问题是为什么gcc(和clang)不会自动执行此操作,因为norm定义可用?
test(vector<100u>&):
        pxor    xmm2, xmm2
        lea     rdx, [rdi+800]
        mov     rax, rdi
.L2:
        movsd   xmm1, QWORD PTR [rax]
        add     rax, 8
        cmp     rdx, rax
        mulsd   xmm1, xmm1
        addsd   xmm2, xmm1
        jne     .L2
        pxor    xmm0, xmm0
.L3:
        movsd   xmm1, QWORD PTR [rdi]
        add     rdi, 8
        cmp     rdx, rdi
        mulsd   xmm1, xmm1
        addsd   xmm0, xmm1
        jne     .L3
        addsd   xmm0, xmm2
        ret
编译器可以计算结果norm并多次重用它。例如使用-Os开关:
test(vector<100u> const&):
        xorps   xmm0, xmm0
        xor     eax, eax
.L2:
        movsd   xmm1, QWORD PTR [rdi+rax]
        add     rax, 8
        cmp     rax, 800
        mulsd   xmm1, xmm1
        addsd   xmm0, xmm1
        jne     .L2
        addsd   xmm0, xmm0
        ret
缺失的优化不是由于非关联浮点数学或某些可观察行为问题造成的。
在未正确互斥的环境中,另一个函数可能会在调用norm之间更改数组中的内容
它可能会发生,但这不是编译器关心的问题(例如/sf/answers/1783087561/)。
使用开关编译示例,-O2 -fdump-tree-all您可以看到:
vector<N>::norm()为纯函数(输出文件.local-pure-const1);.einline)。另请注意,norm使用__attribute__ ((noinline))编译器进行标记会执行 CSE:
test(vector<100u> const&):
    sub     rsp, 8
    call    vector<100u>::norm() const
    add     rsp, 8
    addsd   xmm0, xmm0
    ret
马克·格利斯(可能)是对的。
需要更高级形式的公共子表达式消除来取消内联循环表达式。
| 归档时间: | 
 | 
| 查看次数: | 334 次 | 
| 最近记录: |