下面声明的C ++ norm
类中的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();
}
如果我使用gcc编译器(版本5.4)norm
const
实例化vector
实例化test
多次(并参见上面的-O3
函数)并启用优化(即norm
)然后编译器内联norm
,但仍然多次计算norm
的结果,即使结果不应改变。为什么编译器没有优化对norm
的第二次调用,只计算一次这个结果? This answer似乎表明如果编译器确定norm
函数没有任何副作用,编译器应该执行此优化。为什么在这种情况下不会发生这种情况?
请注意,我确定了编译器使用Compiler Explorer生成的内容,并且下面给出了gcc版本5.4的程序集输出。 clang编译器给出了类似的结果。另请注意,如果我使用gcc的编译器属性来手动将__attribute__((const))
标记为使用norm
的const函数,那么第二个调用会根据我的需要进行优化,但我的问题是为什么gcc (和clang)不会自动执行此操作,因为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
定义可用吗?
foreach($j=2; $j<=10; $j++) {
$objPHPExcel->getActiveSheet()->getCell("D$j")->setDataValidation(clone $objValidation);
}
答案 0 :(得分:4)
编译器可以计算norm
的结果并重复使用多次。例如。 with the -Os
switch:
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
缺少的优化不是由于not-associative-floating-point-math或some observable-behavior-issue。
在一个不正确的互斥环境中,另一个函数可能会在norm调用之间更改数组中的内容
可能会发生,但编译器并不关心(例如https://stackoverflow.com/a/25472679/3235496)。
使用-O2 -fdump-tree-all
开关编译示例,您可以看到:
vector<N>::norm()
为纯函数(输出文件.local-pure-const1
); .einline
)。另请注意,使用norm
compiler performs CSE标记__attribute__ ((noinline))
:
test(vector<100u> const&):
sub rsp, 8
call vector<100u>::norm() const
add rsp, 8
addsd xmm0, xmm0
ret
Marc Glisse(可能)是正确的。
un-inline the recurrent expression需要更高级的 Common Subexpression Elimination 形式。