如果我使用-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;
}
答案 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
(可能只是通过模拟它对常量值的影响)。