Reputation: 27
The following code gives drastically different results when compiling with any optimization flags vs without:
#include <iostream>
#include <cstdint>
// trailing zero count for __uint128_t
int u128_ctz(__uint128_t n) {
int count_hi = __builtin_ctzll(uint64_t(n >> 64));
int count_lo = __builtin_ctzll(uint64_t(n));
return count_lo == 64 ? 64 + count_hi : count_lo;
}
int main() {
__uint128_t one = 1;
__uint128_t t = one << 122;
std::cout << u128_ctz(t) << '\n';
return 0;
}
When compiled plainly with g++ main.cpp
, 122 is printed as I expected. However with optimizations the result becomes 64.
Despite __builtin_ctzll(0ull)
being undefined behavior, a simple print statement above the return shows that it does find the correct value.
My question is not about the undefined behavior of __builtin_ctzll(0ull)
. I am asking why this issue only arises when optimizations are enabled?
Upvotes: -1
Views: 102
Reputation: 5
int u128_ctz(__uint128_t n) {
int count_hi = __builtin_ctzll(uint64_t(n >> 64));
int count_lo = __builtin_ctzll(uint64_t(n));
if (count_lo == 64) {
std::cout << "count_lo == 64\n";
}
return count_lo == 64 ? 64 + count_hi : count_lo;
}
After I added an if statement before return, it seems that the O1 optimization assumes count_lo
will never return 64, so it ignored my condition and returned count_lo
directly.
I think this is the code after O1 optimization:
// O1 optimized
int u128_ctz(__uint128_t n) {
return __builtin_ctzll(uint64_t(n));
}
Upvotes: -2