Home:ALL Converter>Strange GCC6 optimization with builtin function

Strange GCC6 optimization with builtin function

Ask Time:2018-06-15T23:34:11         Author:Bludzee

Json Formatter

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??

Code snippet (broken legacy code!):

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?

Author:Bludzee,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/50878726/strange-gcc6-optimization-with-builtin-function
sepp2k :

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.\n\nIf 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).",
2018-06-15T15:42:36
Jacob Krall :

Undefined behavior doesn't mean \"the value will be arbitrary.\" It means the compiler can do literally anything it wants to. In this case, it looks like the compiler was able to statically verify that as long as value is not 0, i will always be between 0 and 31 inclusive. So it doesn't even bother generating the code for the then-clause.\n\nYou're just lucky demons didn't come out of your nose.\n\nSee also: Undefined behavior can result in time travel, The premature downcast, Why undefined behavior may call a never-called function, and many many many other discussions of UB here.",
2018-06-15T15:42:59
rici :

The compiler assumes Undefined Behaviour doesn't happen. It can make that assumption because if the constraints are violated and behaviour is undefined, any outcome is possible, including the outcome that would result from the incorrect assumption.\n\nIf there is no Undefined Behaviour, then i cannot be negative or greater than 31. On that basis, the condition in the if statement can be optimised at compile time. \n\nThe value actually printed by printf cannot be predicted, so it actually calls printf with whatever i happens to be. In this case, it happened to be 32, but it could have been anything.",
2018-06-15T15:45:32
yy