【发布时间】:2015-11-01 01:43:29
【问题描述】:
此代码为 -O1 和 -O2 提供不同的结果:
/*
Example of a clang optimization bug.
Mark Adler, August 8, 2015.
Using -O0 or -O1 takes a little while and gives the correct result:
47 bits set (4294967296 loops)
Using -O2 or -O3 optimizes out the loop, returning immediately with:
0 bits set (4294967296 loops)
Of course, there weren't really that many loops. The number of loops was
calculated, correctly, by the compiler when optimizing. But it got the
number of bits set wrong.
This is with:
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
*/
#include <stdio.h>
#include <inttypes.h>
/* bit vector of 1<<32 bits, initialized to all zeros */
static uint64_t vec[1 << 26] = {0};
int main(void)
{
/* set 47 of the bits. */
vec[31415927] = UINT64_C(0xb9fe2f2fedf7ebbd);
/* count the set bits */
uint64_t count = 0;
uint64_t loops = 0;
uint32_t x = 0;
do {
if (vec[x >> 6] & ((uint64_t)1 << (x & 0x3f)))
count++;
x++;
loops++;
} while (x);
printf("%" PRIu64 " bits set (%" PRIu64 " loops)\n", count, loops);
return 0;
}
所以这是一个错误吗?或者是否存在某种未定义的行为,编译器有权为其提供不同的结果?
据我所知,从 C99 标准来看,遍历所有 uint32_t 值的 do 循环是有效的,因为最大无符号整数值的增量被明确定义为为零。
涉及无符号操作数的计算永远不会溢出,因为 无法用生成的无符号整数表示的结果 type 以比最大数大一的数为模减少 可以由结果类型表示的值。
【问题讨论】:
-
@black vec 不在堆栈中
-
0xb9fe2f2fedf7ebbd太大而不能成为int,您应该添加ULL。 -
无法在我的 32 位系统上使用 gcc-5.1.1 或 clang3.6.0 进行复制。
-
@mch:
ULL后缀不是必需的。十六进制整数常量的类型是int、unsigned int、long int、unsigned long int、long long int、unsigned long long int中的第一个,其中可以表示其值。0xb9fe2f2fedf7ebbd在具有 64 位long的系统上属于unsigned long int类型,在具有 32 位long的系统上属于unsigned long long int。 -
生成的代码有什么不同?我看到的唯一问题是
uint64_t的 printf 格式。使用:printf("%" PRIu64 "%" PRIu64 "\n", count, loops);(如果 uint_64t 与 ull 相同,则可能没有任何区别)。
标签: c optimization clang c99