Different gcc output for __builtin_clzll on different optimisation levels and wrapped in a function

Viewed 3341

I am puzzled on the behavior / output of the following code, either this is a bug or I am missing something. (Ubuntu 16.04 on skylake arch)

#include <iostream>

int wrap(unsigned long long val) {
    return __builtin_clzll(val);
} 

using namespace std;
int main() {
    cout << __builtin_clzll(0) << " " << wrap(0) << endl;
    cout << __builtin_clzll(1) << " " << wrap(1) << endl;
    cout << __builtin_clzll(2) << " " << wrap(2) << endl;
}

and here are different outputs on different compile settings. I do know that clz may return an undefined result if zero is passed. However the directly inlined call works always fine, but as soon as stack is involved the compiler messes up.

snk@maggy:~/HCS$ g++ -O0 test.cpp -o test
snk@maggy:~/HCS$ ./test
64 4196502
63 63
62 62
snk@maggy:~/HCS$ 

The -O > 0 levels do not change result, I guess gcc is inlining. This is the expected result...

snk@maggy:~/HCS$ g++ -O1 test.cpp -o test
snk@maggy:~/HCS$ ./test
64 64
63 63
62 62

It gets even better with -mlzcnt:

snk@maggy:~/HCS$ g++ -O0 -mlzcnt test.cpp -o test
snk@maggy:~/HCS$ ./test
64 0
63 0
62 1

snk@maggy:~/HCS$ g++ -O1 -mlzcnt test.cpp -o test
snk@maggy:~/HCS$ ./test
64 64
63 63
62 62

snk@maggy:~/HCS$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Thanks, Ch

3 Answers
Related