NO

Author Topic: Another optimizer bug; ignored __int64 cast when doing comparison  (Read 4717 times)

jullien

  • Guest
Here is a sample that shows the issue when -Ox -Ob2 is used

int
main()
{
   unsigned __int64 xx = 0xffffffffffffffe0;
   __int64 yy = -32;

   printf("yy == xx -> %d\n", ((__int64)xx) == yy);
   printf("xx >= 0 -> %d\n", ((__int64)xx) >= 0); // cast is ignored
   printf("yy >= 0 -> %d\n", yy >= 0);
}

Output is:
yy == xx -> 1
xx >= 0 -> 1
yy >= 0 -> 0

neo313

  • Guest
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #1 on: August 14, 2014, 10:15:13 AM »
Confirmed for char, short int, int, long long int. Bug is only present with any level of optimization.

Let me just point out that what are you doing is implementation defined by C Standard.


6.3.1.3

3. Otherwise, the new type is signed and the value cannot be represented in it; either the
result is implementation-defined or an implementation-defined signal is raised.


Of course the result should be consistent, which it isn't in this case.


jullien

  • Guest
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #2 on: August 14, 2014, 10:48:39 AM »
The cast I'm doing is equivalent to reinterpret_cast<__int64>(xx) in C++.
The target has the same size of source (64bits) only interpretation is different.
It is as if I used an intermediate variable:
__int64 temp = (__int64)xx;
if (temp >= 0)

Which is legal and well defined in C.

Event splint does not protest.
This code produce the right result with all compiler/processor I known (I known many of them including C on zOS or vms!).
It used to work with Pelles C until v7 and with v8 RC4 if I recall correctly.

neo313

  • Guest
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #3 on: August 14, 2014, 12:06:25 PM »
The number 18446744073709551584 cannot be represented by an 64 bit signed integer so the rule I mentioned applies.

Of course the result should be consistent and is not.
« Last Edit: August 14, 2014, 12:24:32 PM by neo313 »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #4 on: August 14, 2014, 02:05:59 PM »
Christian I agree with you, the cast should simply force the variable interpretation.
neo313 the point you exposed is reasonable, but if you look at the assembler code you will see that the comparison is made for unsigned interpretation (using jb and ja processor instructions), while without optimizations the comparison performed is for signed integers (processor instructions jg and jl) as should be. So, as stated by the rule, the implementation-defined result should be ignore the cast, but this action can happen only at compile time when the values are not defined yet. Acting this way the compiler should refuse to use the cast even for correct values. This makes no sense at all.
In my opinion this is a bug of the optimizer.
« Last Edit: August 14, 2014, 02:23:29 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

neo313

  • Guest
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #5 on: August 14, 2014, 02:34:46 PM »
@frankie

If you read my first post you will see that I confirmed that the bug is there.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #6 on: August 14, 2014, 05:20:15 PM »
@frankie

If you read my first post you will see that I confirmed that the bug is there.
Hi neo313,
yes I have read it. I would just enforce that your point about the paragraph 6.3.1.3 of the C standard is correct and appropriate.  :D
Following your good observation that the 64 bits representation of -32 is equivalent to 18446744073709551584 in unsigned form I have examined the compiler behaviour at assembly level to see if there was any conversion overflow check and I discovered that this is not our case and added some technical detail. That's all 8)
« Last Edit: August 14, 2014, 05:28:18 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

jullien

  • Guest
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #7 on: August 14, 2014, 07:09:40 PM »
I have examined the compiler behaviour at assembly level to see if there was any conversion overflow check and I discovered that this is not our case and added some technical detail.

This is also the behavior of all C I know on all processor I know whether they are big or little endian, from 16 to 64bits
I can't remember how behave the few 8bit processors I work on - z80 8080 - but I doubt they check overflow.
They take unsigned value from memory or register and use signed instruction to compute the result.
« Last Edit: August 14, 2014, 07:11:22 PM by jullien »

Dickie-Doo

  • Guest
Re: Another optimizer bug; ignored __int64 cast when doing comparison
« Reply #8 on: August 16, 2014, 01:37:33 AM »
I just tried to upgrade from RC4 to RC6 (I missed RC5!) and my program failed to run properly.  The cause turns out to be another version of the casting problem.  I was casting an unsigned long long to a signed long long in order to test the ms-bit.  Works as expected with RC4, but with RC6 the cast is ignored.  Work-around is to substitute an AND with 0x8000000000000000 - something I was trying to avoid!  (As described above, an embedded assignment to a dummy signed variable also works.)  I concur with those who say that most C compilers interpret a cast from signed to unsigned or vice-versa as equivalent to assignment to a dummy variable of the 'cast' type.