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

托·克林伯格

考虑下面的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在所有情况下,编译后的程序集都会写入所有15个零,然后再用42个覆盖其中的10个。

我想可能还没有针对这种情况编写任何优化,但是对于我来说,这似乎是一个显而易见的常见情况。是否有阻碍优化的因素?

我在x86-32 Linux上并使用了以下命令:

gcc -std=c99 -S -O3 hello.c
clang -std=c99 -S -O3 hello.c
巴西勒·斯塔林凯维奇

这不是一个很科学的解释,而只是一种直觉(但是,我确实知道GCC的某些内部知识)。

为了可靠地进行所需的优化,编译器必须管理子数组切片然后,它变得非常复杂且容易出错。最优化的编译器可能会消耗大量内存(用于子数组的符号表示)和大量编译时间。这通常是不值得的工作(最好在编译器内部花费以优化循环)。

顺便说一句,GCC有一个插件框架和MELT扩展(MELT是扩展GCC的一种轻快的领域专用语言,我是MELT的主要作者)。因此,您可以尝试添加新的优化遍(通过MELT扩展或某些C ++插件)来完成工作。您很快就会意识到,您的传递可能是非常特殊的,或者将需要处理大量的GCC内部表示,并且很可能会浪费编译时间和内存,而获得的收益却很少。

请注意,GCC和Clang都巧妙地展开了两个循环(这在性能方面很重要)。

顺便说一句,Frama-C(由同事开发的用于C程序的静态分析器)价值分析器似乎能够推断出您的arr

因此,可以随时将优化添加到GCC中。如果您不知道(或没有时间-数月或数年)如何添加它,请随时向能够增强GCC的公司或组织付款,以满足您的需求。要使这种优化在有趣的情况下进行,可能需要一个100万欧元(或美元)/ 3年的项目。

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

具有这种优化功能的编译器将需要一些启发式方法来禁用它们(例如,如果arr是一百万个成员的数组,而您正在编写一些Erasthothenes的筛子,则可能不值得编译器付出任何努力来保持所有子切片的并集)。综合索引)。

顺便说一句,您会接受二十倍慢的优化编译器(在编译时变慢)来获得增益(运行时可能是百分之一的百分比),这种增益在实践中很少发生并且不是很重要吗?最后,我不认为这是优化常见情况YMMV。

您可能对像PIPS4U这样的源到源变压器感兴趣

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么编译器不优化此代码

为什么Java编译器不理解此变量总是初始化的?

为什么编译器禁止初始化数组?

为什么在某些优化级别上,编译器会警告未初始化的边缘迭代器?

编译器会优化集合初始化吗?

Visual Studio生成“错误:未初始化的本地变量'x'”,而在线编译器不生成-为什么?

为什么编译器没有优化此负载

为什么Kotlin编译器需要var属性的显式初始化程序?

为什么编译器会警告不要在初始化列表中隐藏成员?

为什么Kotlin编译器不强迫我初始化接口中定义的val?

为什么编译器不优化中断代码?

如果将错误的参数类型传递给结构初始化程序列表,编译器为什么不生成编译错误?

为什么编译器不抱怨此错误?

为什么在循环中初始化数组时Rust编译器为什么会给出未初始化的变量错误?

MSVC为什么不初始化此const结构?

何时允许编译器优化自动括号样式的初始化?

为什么编译器说如果要求变量在循环中通过才可能不初始化变量?

为什么编译器报告“可能在此函数中未初始化使用”?

为什么编译器将带有方括号()的数组初始化标记为错误?

为什么我的开关块中出现“变量可能尚未初始化”的编译器错误?

初始化易失性数组时,为什么编译器会生成此类代码?

为什么编译器接受带有长双精度字面量的浮点数的初始化?

为什么零初始化不是c ++中未初始化变量的默认值?有编译器选项可以强制执行吗?

为什么C和C ++编译器将显式初始化和默认初始化的全局变量放在不同的段中?

为什么编译器不再使用严格的别名来优化此UB

为什么编译器未使用-O3优化此C ++成员函数?

为什么编译器将此变量初始化为错误的值?这是对齐问题吗?

为什么普通的c ++编译器不优化对象副本?

为什么我的C ++编译器不优化这些写入的内存?