With GCC6 and the code snippet below, this test
if (i > 31 || i < 0) {
is false, and this printf is executed
printf("i > 31 || i < 0 is FALSE, where i=%d", i);
and produces this very weird output (GCC6):
i > 31 || i < 0 is FALSE, where i=32 /* weird result with GCC6 !!! */
whereas with GCC4 I get:
i > 31 || i < 0 is true, where i=32 /* result Ok with GCC4 */
which looks perfectly alright.
How can this be??
static int check_params(... input parameters ...) {
/* Note that value can be 0 (zero) */
uint32_t value = ....
int i;
i = __builtin_ctz(value);
if (i > 31 || i < 0) {
printf("i > 31 || i < 0 is true, where i=%d", i);
/* No 1 found */
return 0;
} else {
printf("i > 31 || i < 0 is FALSE, where i=%d", i);
}
return i;
}
According to the documentation about GCC builtin functions, calling __builtin_ctz(0) must be avoided:
Built-in Function: int __builtin_ctz (unsigned int x) Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.
So obviously, a solution to the coding error is to simply check the value before calling __builtin_ctz(value). This is clear and understood.
I could just stop there and move to other topics...but still, I don't understand how I could possibly (with the broken code), get the following output:
i > 31 || i < 0 is FALSE, where i=32 /* weird result with GCC6 !!! */
A weird GCC6 optimization or something?
Just in case it matters at all:
Cross-compiler: arm-linux-gcc
Architecture: -march=armv7-a
Any idea?
Barring undefined behaviour, __builtin_ctz
will always return a number between 0 and 31 and GCC knows this. Therefore the check i > 31 || i < 0
will always be false (again barring undefined behaviour) and can be optimized away.
If you look at the generated assembly, you'll see that the condition doesn't appear in the code at all (nor does the then-case).