C++ 为什么这个程序没有优化呢?

C++ 为什么这个程序没有优化呢?,c++,optimization,strength-reduction,C++,Optimization,Strength Reduction,考虑以下简单程序(改编自): #包括 int main(int argc,字符**argv){ int mul1[10]={4,1,8,6,3,2,5,8,6,7};//总和=50 int mul2[10]={4,1,8,6,7,9,5,1,2,3};//总和=46 intx1=std::atoi(argv[1]); intx2=std::atoi(argv[2]); int结果=0; //对于mul1/mul2中的每个元素,用结果中的x1/x2累加乘积 对于(int i=0;i

考虑以下简单程序(改编自):

#包括
int main(int argc,字符**argv){
int mul1[10]={4,1,8,6,3,2,5,8,6,7};//总和=50
int mul2[10]={4,1,8,6,7,9,5,1,2,3};//总和=46
intx1=std::atoi(argv[1]);
intx2=std::atoi(argv[2]);
int结果=0;
//对于mul1/mul2中的每个元素,用结果中的x1/x2累加乘积
对于(int i=0;i<10;++i){
结果+=x1*mul1[i]+x2*mul2[i];
}
返回结果;
}
我认为它在功能上等同于以下一个:

#include <cstdlib>

int main(int argc, char** argv) {
    int x1 = std::atoi(argv[1]);
    int x2 = std::atoi(argv[2]);

    return x1 * 50 + x2 * 46;
}
#包括
int main(int argc,字符**argv){
intx1=std::atoi(argv[1]);
intx2=std::atoi(argv[2]);
返回x1*50+x2*46;
}
然而,而且似乎无法进行这样的优化,即使使用
-Ofast
。(顺便说一下,编译器之间生成的程序集有很大的不同!)。但是,当从方程中删除
mul2
x2
时,即使使用
-O2
,也能够执行类似的优化


是什么阻止了两个编译器将第一个程序优化为第二个程序?

完整的表达式太复杂了,甚至不适合叮当作响。如果将其拆分,则所有内容都会再次得到优化:

int result1 = 0;
int result2 = 0;

for (int i = 0; i < 10; ++i) {
    result1 += x1 * mul1[i];
    result2 += x2 * mul2[i];
}

std::cout << (result1 + result2);
int result1=0;
int result2=0;
对于(int i=0;i<10;++i){
结果1+=x1*mul1[i];
结果2+=x2*mul2[i];
}

我不是编译器程序员,所以这只能是猜测。我想,答案是@dlask答案的一部分,也是当您从表达式中删除
x2
mul2
时,clang进行优化的一部分

编译器可以优化它所能做的一切。但我也认为优化编译器已经是一个庞大而复杂的程序,其中的bug可能会产生很高的后果,因为它们几乎是其他一切的基础(Python大多数当前的解释器都是用…C编写的)


因此,必须在优化器的效率和复杂性之间取得平衡,我认为这个示例程序对于gcc来说已经超出了它的范围,对于clang来说也差不多了。没有什么可以阻止他们进行这种优化,只是对于当前版本的编译器来说太复杂了。

@buttiful butefly在一般情况下,操作x1*mul1[i]会导致溢出,我很惊讶当您从等式中删除
x2*mul2[i]
时,clang能够优化循环。就我个人而言,我觉得人们不应该期望编译器优化器带来任何东西;收到的任何东西都是奖金@vlad溢出是UB,因此可以假定在优化时不会发生。@VLADFROMMOSCO也可以将溢出视为模运算,因此显示的优化应该产生相同的结果(即,(a1*x+a2*x)%overflow==(a1*x%溢出+a2*x%溢出)%overflow),这实际上不是一个简单的优化。是的,这是合法的,但它需要以正确的顺序传递一组非常复杂的优化器才能做到这一点。+1,但我不确定这是否是一个复杂的问题。优化是由编译器开发人员创建的,与任何其他程序员一样,他们也必须确定优先级。程序很少像示例中那样包含硬编码的数字,一个优秀的程序员无论如何都会手工优化代码。因此,让优化器处理这个特殊情况(以及一百万个与某些模型不完全匹配的其他简单情况)只是浪费资源。@eran我强烈不同意你的看法。有时,手工优化会降低可读性,从而降低可维护性。低可维护性会导致更大的资源浪费(时间)。生成最终代码是编译器的职责,所以它应该尽最大努力,利用可用的信息,生成最佳结果。
int result1 = 0;
int result2 = 0;

for (int i = 0; i < 10; ++i) {
    result1 += x1 * mul1[i];
    result2 += x2 * mul2[i];
}

std::cout << (result1 + result2);