This code gives different results for -O1 and -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;
}
So is this a bug? Or is there somehow an undefined behavior in there, that the compiler is within its rights to give different results for?
As far as I can tell from the C99 standard, the do
loop to go through all uint32_t
values is valid since the increment of the largest unsigned integer value is well defined to result in zero.
A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.
0xb9fe2f2fedf7ebbd
is too large to be anint
, you should addULL
. - mchULL
suffix is not necessary. The type of a hexadecimal integer constant is of the first ofint
,unsigned int
,long int
,unsigned long int
,long long int
,unsigned long long int
in which its value can be represented.0xb9fe2f2fedf7ebbd
is of typeunsigned long int
on a system with 64-bitlong
, orunsigned long long int
on a system with 32-bitlong
. - Keith Thompsonuint64_t
. Use:printf("%" PRIu64 "%" PRIu64 "\n", count, loops);
(might not make any difference if if uint_64t is same ull). - P.P