dsa
dsa

Reputation: 27

g++ very different behaviour with vs without optimization flags

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

Answers (1)

Phạm Anh T&#250;
Phạm Anh T&#250;

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

Related Questions