Created attachment 23749 [details] Small code to show uint64_t / int64_t difference Attached code shows a comparison of converted int->float values: ( (float)(ui+1) != ((float)ui) + 1.f ) This comparison fails beginning at number 16777216 for ui of type uint64_t, but it doesn't fail there for ui of type int64_t. Tested in gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5), Ubuntu 10.10 32 bits, atom processor. Compiled with no parameters: gcc test.c && ./a.out Tested also in mingw 4.4.5, same problem. Tested in MSVC (vs2010) too, and it doesn't fail early for uint64_t, like gcc does.
Even simpler code. uint64_t and int64_t converted to floats differ beginning at 16 million. Fails at value 16777217: ----------------------->8----------------------- #include <stdint.h> #include <stdio.h> int main() { uint64_t ui ; int64_t i ; for( i=0, ui=0 ; ; i++ , ui++ ) if( (float) i != (float) ui ) { printf("error: ui=%lld\n" , ui ) ; break ; } return 0 ; } -----------------------8<----------------------- Fails on default params, -O0, -O3...
Possibly an instance of PR 323.
From my understanding, a positive number should be casted to exactly the same floating value representation regardless if the variable is signed or unsigned. In fact, checking the failing values, we see this: uint64_t ui: 16777217 -> (float) ui:16777216.000000 ( ui - 1 ) uint64_t ui: 16777218 -> (float) ui:16777218.000000 ( correct ) uint64_t ui: 16777219 -> (float) ui:16777220.000000 ( ui + 1 ) The casting of a uint64_t value to float wiggles around the correct value, but an int64_t value stays correct. int64_t i : 16777217 -> (float) i:16777217.000000 ( correct ) int64_t i : 16777218 -> (float) i:16777218.000000 ( correct ) int64_t i : 16777219 -> (float) i:16777219.000000 ( correct )
> From my understanding, a positive number should be casted to exactly the same > floating value representation regardless if the variable is signed or unsigned. > In fact, checking the failing values, we see this: Above 2^24 and below 2^25, only even integers are not rounded when converted to float and odd integers are rounded. I think it is what you report in comment #3.
(In reply to comment #4) > Above 2^24 and below 2^25, only even integers are not rounded when converted to > float and odd integers are rounded. I think it is what you report in comment > #3. Could be, but why would it only happen for uint64_t, and not int64_t?
The issue seems to be a x87 specific one. We expand the conversions to ;; if (D.2537_5 != D.2538_6) (insn 22 20 23 4 t.c:9 (set (reg:SF 66) (float:SF (reg/v:DI 62 [ i ]))) -1 (nil)) (insn 23 22 24 4 t.c:9 (set (reg:XF 68) (float:XF (reg/v:DI 63 [ ui ]))) -1 (nil)) (insn 24 23 25 4 t.c:9 (set (reg:CCGOC 17 flags) (compare:CCGOC (subreg:SI (reg/v:DI 63 [ ui ]) 4) (const_int 0 [0x0]))) -1 (nil)) and later (insn 55 20 56 4 t.c:9 (parallel [ (set (reg:SF 9 st(1) [66]) (float:SF (reg/v:DI 1 dx [orig:62 i ] [62]))) (clobber (mem/c:DI (plus:SI (reg/f:SI 7 sp) (const_int 16 [0x10])) [0 S8 A64])) ]) 226 {*floatdisf2_i387_with_temp} (nil)) (insn 56 55 24 4 t.c:9 (parallel [ (set (reg:XF 8 st [68]) (float:XF (reg/v:DI 1 dx [orig:62 i ] [62]))) (clobber (mem/c:DI (plus:SI (reg/f:SI 7 sp) (const_int 16 [0x10])) [0 S8 A64])) ]) 230 {*floatdixf2_i387_with_temp} (nil)) so for some reason we miss truncation to SFmode. We also seem to account for the fact that the used fildq instruction operates on signed input only by compensating with the addition of a bias - but that obviously changes rounding behavior and is not suitable w/o -funsafe-math-optimizations (we do add a FP bias, not an integer bias, and we probably think using XFmode for it makes it ok). With -std=c99 and GCC 4.5 the code works as expected as we properly truncate the XFmode result, that is -fexcess-precision=standard. *** This bug has been marked as a duplicate of bug 323 ***