为什么编译器不优化这种初始化?

时间:2015-03-11 16:54:19

标签: c compiler-optimization

考虑以下C代码:

extern void foo(int* ip);

void myfunc(void)
{
    int arr[15] = {0};
    for (int i=0; i<10; i++)
    {
        arr[i] = 42;
    }

    foo(arr);
}

我尝试使用gcc和clang,-O3-Os。在所有情况下,编译的程序集在用42.编写其中10个之前写入所有15个零。

我想可能只是没有针对这种情况编写优化,但对我来说这似乎是一个相当明显和常见的情况。有没有阻止优化的东西?

我在x86-32 Linux上使用这些命令:

gcc -std=c99 -S -O3 hello.c
clang -std=c99 -S -O3 hello.c

1 个答案:

答案 0 :(得分:9)

这不是一个非常科学的解释,而只是一种直觉(但是,我确实碰巧知道了GCC内部的一些)。

为了可靠地进行所需的优化,编译器必须管理子阵列 slice 。然后它变得非常复杂且容易出错。优化那么多的编译器可能会占用大量内存(用于子数组的符号表示)和大量的编译时间。这通常不值得努力(最好在编译器内部优化循环)。

BTW,GCC有一个插件框架和MELT扩展(MELT是扩展GCC的lispy域特定语言,我是MELT的主要作者)。因此,您可以尝试添加新的优化传递(通过MELT扩展或某些C ++插件)来完成工作。你很快就会意识到你的传递要么非常具体,要么需要处理大量的GCC内部表示,并且很可能会使编译时间和内存损失很少。

请注意,GCC和Clang都巧妙地展开了两个循环(这在很大程度上取决于性能)。

BTW,Frama-C(由同事开发的C程序的静态分析器)值分析器似乎能够推断出关于arr的良好属性

因此,请随意将该优化添加到GCC。如果您不知道(或没有时间 - 许多个月或几年)如何添加它,请随时向能够根据您的需求增强GCC的公司或组织付款。可能需要一百万欧元(或美元)/ 3年的项目来完成有趣案例的优化工作。

如果您认真考虑花这么多钱,请通过电子邮件与我联系。

具有这种优化的编译器需要一些启发式来禁用它们(例如,如果arr是一个百万个成员的数组,并且你编写了一些sieve of Erasthothenes,则可能不值得编译器工作在编译时保留所有复合索引子片的联合。)

BTW,你会接受一个20倍慢的优化编译器(在编译时更慢)获得增益(在运行时可能只有百分之几),这在实践中很少发生并且不是很重要吗?最后,我不认为这是用于优化的常见案例。 YMMV。

您可能对源代码感兴趣,例如PIPS4U