Clang真的很聪明吗?

时间:2014-05-29 05:09:29

标签: c++ c++11 clang llvm compiler-optimization

如果我使用-O3 -fno-vectorize使用Clang 3.3编译以下代码,即使删除注释行,我也会获得相同的汇编输出。代码类型将所有可能的32位整数置于浮点数并计算[0,1]范围内的值。 Clang的优化器实际上是否足够聪明,以致当被处理为浮点数时0xFFFFFFFF不在[0,1]范围内,所以忽略对fn的第二次调用?删除第二个调用时,GCC会生成不同的代码。

#include <limits>
#include <cstring>
#include <cstdint>

template <class TO, class FROM>
inline TO punning_cast(const FROM &input)
{
    TO out;
    std::memcpy(&out, &input, sizeof(TO));
    return out;
}

int main()
{
    uint32_t count = 0;

    auto fn = [&count] (uint32_t x) {
        float f = punning_cast<float>(x);
        if (f >= 0.0f && f <= 1.0f)
            count++;
    };

    for(uint32_t i = 0; i < std::numeric_limits<uint32_t>::max(); ++i)
    {
        fn(i);
    }
    fn(std::numeric_limits<uint32_t>::max()); //removing this changes nothing

    return count;
}

见这里:http://goo.gl/YZPw5i

1 个答案:

答案 0 :(得分:11)

是的,看起来Clang真的很聪明。

测试:

#include <limits>
#include <cstring>
#include <cstdint>

template <class TO, class FROM>
inline TO punning_cast(const FROM &input)
{
    TO out;
    std::memcpy(&out, &input, sizeof(TO));
    return out;
}

int main()
{
    uint32_t count = 0;

    auto fn = [&count] (uint32_t x) {
        float f = punning_cast<float>(x);
        if (f >= 0.0f && f <= 1.0f)
            count++;
    };

    for(uint32_t i = 0; i < std::numeric_limits<uint32_t>::max(); ++i)
    {
        fn(i);
    }
#ifdef X
    fn(0x3f800000); /* 1.0f */
#endif

    return count;
}

结果:

$ c++ -S -DX -O3 foo.cpp -std=c++11 -o foo.s
$ c++ -S -O3 foo.cpp -std=c++11 -o foo2.s
$ diff foo.s foo2.s
100d99
<   incl    %eax

观察到Clang已将调用转换为fn(0x3f800000)只是一个增量指令,因为该值解码为1.0。这是正确的。

我的猜测是Clang正在跟踪函数调用,因为它们只涉及常量,并且Clang能够通过类型惩罚跟踪memcpy(可能只是通过模拟它对常量值的影响)。