考虑以下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
答案 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,则可能不值得编译器工作在编译时保留所有复合索引子片的联合。)
您可能对源代码感兴趣,例如PIPS4U