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

时间:2018-01-19 23:05:51

标签: gcc type-conversion clang compiler-optimization

请考虑以下代码:

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 Optimizing software in C++中的例7.26a和7.26b,应该做同样的事情; bar更加“高效”,因为我们在每次迭代时都不进行整数到浮点转换,而是更便宜的浮点数(在x86_64上)。

Here是这两个函数的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都执行预期的优化,尽管不完全相同(参见this question)。

1 个答案:

答案 0 :(得分:1)

您要为浮点数启用induction variable optimization。这种优化在浮点域中通常不安全,因为它会更改程序语义。在您的示例中,因为初始值(0.0)和步长(2.0)都可以用IEEE格式精确表示,所以它会起作用,但这在实践中很少见。

可以在-ffast-math下启用它,但是似乎在GCC中这并不重要,因为它很早就拒绝了非积分归纳变量(请参见tree-scalar-evolution.c)。

如果您认为这是一个重要用例,则可以考虑在GCC Bugzilla处提交请求。