Weird optimization

Hi,

Moving to CLANG toolset we bumped in a problem illustrated by the following small reproducer. Reproducible with clang34, clang35, clang36 on FreeBSD 9.3 x64. It is reproducible only with -O3. The program works as expected on GCC and MSVC.

#include <stdio.h>
#include <stdint.h>

bool test_fp_lt(int64_t x) {
     // Take care of -0
     return (-x) > 0;
}

void test_lt(int64_t x, bool res) {
     bool r = test_fp_lt(x);
     if(r != res) {
         printf("test_lt failed for %016lx: expected %d, got %d\n", x, res, r);
     }
}

int main() {
     test_lt(0x0000000000000000ul, false);
     test_lt(0x8000000000000000ul, false);
     test_lt(0x4000000000000000ul, false);
     test_lt(0x8000000000000001ul, true);
     test_lt(0xFFFFFFFFFFFFFFF0ul, true);
     return 0;
}

The program should not print anything. It fails for 0x8000000000000000ul, though.

The geneated code for test_fp_lt is:
shr rdi, 63
mov al, dil

whereas the expected working code (from GCC) is
neg rdi
test rdi, rdi
setg al

As far as I understand the compiler co,piler optimizes (-x) > 0 into x < 0. What is wrong here?

Best regards,
Artem

Hi,
I think you have a problem with nasal demons:

$ gcc-4.9.2 -fsanitize=undefined -O3 -Wall -pedantic -Wextra minus.cpp
$ ./a.out
minus.cpp:6:17: runtime error: negation of -9223372036854775808 cannot
be represented in type 'long int'; cast to an unsigned type to negate
this value to itself

Hi Csaba,

Yes, thanks. nasal demons, indeed. I forgot that the signed integer overflow causes undefined behavior unlike unsigned integer overflow, which causes wrap around.

The code
     return (long)(0ul - (unsigned long)x) > 0;
does what I want.

I am impressed by clang's ability to use this undefinedness to enable optimizations like (-x) > 0 to x < 0, which seems to be valid for all valid arguments.

Best regards,
Artem

This is, in fact, a great illustration of an optimization enabled by
undefined behavior. The compiler can say: "I don't have to make it
work correctly for 0x8000000000000000ul, and for every other case it's
faster this way".

A very good article about undefined behavior: