为什么 clang 和 gcc 不能优化这种 int 到 float 的转换?

2024-03-26

考虑以下代码:

void foo(float* __restrict__ a)
{
    int i; float val;
    for (i = 0; i < 100; i++) {
        val = 2 * i;
        a[i] = val;
    }
}

void bar(float* __restrict__ a)
{
    int i; float val = 0.0;
    for (i = 0; i < 100; i++) {
        a[i] = val;
        val += 2.0;
    }
}

它们基于 Agner Fog 中的示例 7.26a 和 7.26b用 C++ 优化软件 http://www.agner.org/optimize/optimizing_cpp.pdf并且应该做同样的事情;bar更“高效”,因为我们不在每次迭代时进行整数到浮点转换,而是进行更便宜的浮点加法(在 x86_64 上)。

Here https://godbolt.org/g/c7LXQD是这两个函数的 clang 和 gcc 结果(没有矢量化和展开)。

问题:在我看来,用常量值的加法替换循环索引的乘法的优化 - 当这有益时 - 应该由编译器执行,即使(或者可能特别是如果)涉及类型转换。为什么这两个函数没有发生这种情况?

请注意,如果我们使用 int 而不是 float:

void foo(int* __restrict__ a)
{
    int i; int val = 0;
    for (i = 0; i < 100; i++) {
        val = 2 * i;
        a[i] = val;
    }
}

void bar(int* __restrict__ a)
{
    int i; int val = 0;
    for (i = 0; i < 100; i++) {
        a[i] = val;
        val += 2;
    }
}

clang 和 gcc 都执行预期的优化,尽管方式不完全相同(请参阅这个问题 https://stackoverflow.com/questions/48354636/is-multiplying-via-the-addressing-mode-a-good-idea).


您正在寻找启用归纳变量优化 https://en.wikipedia.org/wiki/Induction_variable#Application_to_strength_reduction对于浮点数。这种优化在浮点领域通常是不安全的,因为它会改变程序语义。在你的例子中它会起作用,因为两个初始值(0.0)和步骤(2.0) 可以用 IEEE 格式精确表示,但在实践中这种情况很少见。

它可以在下面启用-ffast-math但在 GCC 中这似乎并没有被认为是重要的情况,因为它很早就拒绝了非整数归纳变量(参见树标量进化.c https://github.com/gcc-mirror/gcc/blob/428c12fad2565e3568d2d822942919da78350dc0/gcc/tree-scalar-evolution.c#L3326).

如果您认为这是一个重要的用例,您可以考虑在以下地址提交请求:GCC Bugzilla https://gcc.gnu.org/bugzilla/.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 clang 和 gcc 不能优化这种 int 到 float 的转换? 的相关文章

随机推荐