Control: forwarded -1 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
On Thu, 24 Sep 2015 18:42:14 +0200 Miroslav Urbanek <m...@miroslavurbanek.com> wrote: > I believe I've found a bug in GCC that affects plymouth and maybe > other packages on i386. The following minimal code produces an > incorrect result. At least it's an unexpected result ... seems like you are running in some excess precision issue, probably PR323 I can also reproduce it on amd64 when explicitly using the 387 FPU: $ gcc-5 -O1 -mfpmath=387 -o test test.c && ./test 100 f = 9999999.000000 d = 999999872.000000 g = 999999872.000000 fractional part of d is 28.000000 and I cannot reproduce it on armhf (in qemu). gcc-5 -O2 -o test test.c && ./test 100 f = 9999999.000000 d = 999999872.000000 g = 999999872.000000 fractional part of d is 0.000000 amd64 disassembly with -mfpmath=387: -O0: 0000000000400546 <main>: # 400546: 55 push %rbp # 400547: 48 89 e5 mov %rsp,%rbp # 40054a: 48 83 ec 40 sub $0x40,%rsp # 40054e: 89 7d dc mov %edi,-0x24(%rbp) # 400551: 48 89 75 d0 mov %rsi,-0x30(%rbp) 400555: d9 05 6d 01 00 00 flds 0x16d(%rip) # 4006c8 <_IO_stdin_used+0x38> 40055b: d9 5d fc fstps -0x4(%rbp) = f (float) # 40055e: 48 8b 45 d0 mov -0x30(%rbp),%rax # 400562: 48 83 c0 08 add $0x8,%rax # 400566: 48 8b 00 mov (%rax),%rax # 400569: 48 89 c7 mov %rax,%rdi # 40056c: e8 cf fe ff ff callq 400440 <atoi@plt> 400571: 89 45 c8 mov %eax,-0x38(%rbp) = argv[1] (int) 400574: db 45 c8 fildl -0x38(%rbp) int_to_extended(argv(1)) 400577: d8 4d fc fmuls -0x4(%rbp) 40057a: dd 5d f0 fstpl -0x10(%rbp) = d (double) 40057d: dd 45 f0 fldl -0x10(%rbp) 400580: d9 5d ec fstps -0x14(%rbp) = g (float) 400583: f2 0f 10 45 f0 movsd -0x10(%rbp),%xmm0 400588: f2 0f 2c c0 cvttsd2si %xmm0,%eax (int)d (double2int with truncation) 40058c: 89 45 e8 mov %eax,-0x18(%rbp) = i (int) # 40058f: d9 45 fc flds -0x4(%rbp) print f # 400592: dd 5d c8 fstpl -0x38(%rbp) # 400595: f2 0f 10 45 c8 movsd -0x38(%rbp),%xmm0 # 40059a: bf 94 06 40 00 mov $0x400694,%edi # 40059f: b8 01 00 00 00 mov $0x1,%eax # 4005a4: e8 67 fe ff ff callq 400410 <printf@plt> # 4005a9: 48 8b 45 f0 mov -0x10(%rbp),%rax print d # 4005ad: 48 89 45 c8 mov %rax,-0x38(%rbp) # 4005b1: f2 0f 10 45 c8 movsd -0x38(%rbp),%xmm0 # 4005b6: bf 9c 06 40 00 mov $0x40069c,%edi # 4005bb: b8 01 00 00 00 mov $0x1,%eax # 4005c0: e8 4b fe ff ff callq 400410 <printf@plt> # 4005c5: d9 45 ec flds -0x14(%rbp) print g # 4005c8: dd 5d c8 fstpl -0x38(%rbp) # 4005cb: f2 0f 10 45 c8 movsd -0x38(%rbp),%xmm0 # 4005d0: bf a4 06 40 00 mov $0x4006a4,%edi # 4005d5: b8 01 00 00 00 mov $0x1,%eax # 4005da: e8 31 fe ff ff callq 400410 <printf@plt> 4005df: db 45 e8 fildl -0x18(%rbp) int_to_extended(i) 4005e2: dd 45 f0 fldl -0x10(%rbp) double_ro_extended(d) 4005e5: de e1 fsubp %st,%st(1) 4005e7: dd 5d c8 fstpl -0x38(%rbp) = d-i # 4005ea: f2 0f 10 45 c8 movsd -0x38(%rbp),%xmm0 print d-i # 4005ef: bf ac 06 40 00 mov $0x4006ac,%edi # 4005f4: b8 01 00 00 00 mov $0x1,%eax # 4005f9: e8 12 fe ff ff callq 400410 <printf@plt> # 4005fe: 90 nop # 4005ff: c9 leaveq # 400600: c3 retq -O1: 0000000000400546 <main>: # 400546: 48 83 ec 28 sub $0x28,%rsp # 40054a: 48 8b 7e 08 mov 0x8(%rsi),%rdi # 40054e: ba 0a 00 00 00 mov $0xa,%edx # 400553: be 00 00 00 00 mov $0x0,%esi # 400558: e8 e3 fe ff ff callq 400440 <strtol@plt> 40055d: 48 89 44 24 08 mov %rax,0x8(%rsp) = argv[1] (long) 400562: db 44 24 08 fildl 0x8(%rsp) int_to_extended(argv(1)) fpu stack: argv(1) 400566: d9 05 4c 01 00 00 flds 0x14c(%rip) # 4006b8 <_IO_stdin_used+0x38> fpu stack: f, argv(1) 40056c: dc c9 fmul %st,%st(1) fpu stack: f, d 40056e: d9 c9 fxch %st(1) fpu stack: d, f 400570: d9 54 24 08 fsts 0x8(%rsp) = g (float) 400574: dd 5c 24 10 fstpl 0x10(%rsp) = d (double) # 400578: dd 5c 24 18 fstpl 0x18(%rsp) print f # 40057c: f2 0f 10 44 24 18 movsd 0x18(%rsp),%xmm0 # 400582: bf 84 06 40 00 mov $0x400684,%edi # 400587: b8 01 00 00 00 mov $0x1,%eax # 40058c: e8 7f fe ff ff callq 400410 <printf@plt> # 400591: d9 44 24 08 flds 0x8(%rsp) print g !!! # 400595: dd 5c 24 18 fstpl 0x18(%rsp) # 400599: f2 0f 10 44 24 18 movsd 0x18(%rsp),%xmm0 # 40059f: bf 8c 06 40 00 mov $0x40068c,%edi # 4005a4: b8 01 00 00 00 mov $0x1,%eax # 4005a9: e8 62 fe ff ff callq 400410 <printf@plt> # 4005ae: d9 44 24 08 flds 0x8(%rsp) print g # 4005b2: dd 5c 24 18 fstpl 0x18(%rsp) # 4005b6: f2 0f 10 44 24 18 movsd 0x18(%rsp),%xmm0 # 4005bc: bf 94 06 40 00 mov $0x400694,%edi # 4005c1: b8 01 00 00 00 mov $0x1,%eax # 4005c6: e8 45 fe ff ff callq 400410 <printf@plt> 4005cb: f3 0f 2c 44 24 08 cvttss2si 0x8(%rsp),%eax (int)g (float2int with truncation) 4005d1: 89 44 24 08 mov %eax,0x8(%rsp) = i (int) 4005d5: db 44 24 08 fildl 0x8(%rsp) int_to_extended(i) 4005d9: dc 6c 24 10 fsubrl 0x10(%rsp) 4005dd: dd 5c 24 08 fstpl 0x8(%rsp) = d-i # 4005e1: f2 0f 10 44 24 08 movsd 0x8(%rsp),%xmm0 print d-i # 4005e7: bf 9c 06 40 00 mov $0x40069c,%edi # 4005ec: b8 01 00 00 00 mov $0x1,%eax # 4005f1: e8 1a fe ff ff callq 400410 <printf@plt> # 4005f6: 48 83 c4 28 add $0x28,%rsp # 4005fa: c3 retq What's the result type of float * int ? Definitively not double, but float. (Just the intermediate result in the x87 fpu has extended precision.) So I don't think the compiler is wrong considering d and g to contain the same information, since the same *float* value was assigned to both variables. Therefore it considers (int)d and int(g) to be the same, ignoring that there are some excess precision bits in the double representation which cause your trouble. So it's actually using i = (int)g and therefore computing d-(int)g; So what you are actually computing is the difference of the float and double representation of 999999900 (which cannot be represented as float exactly.) printf("%f\n", 999999900.0d - 999999900.0f); ==> 28.000000 Just for completeness, gcc-4.6 -O1: Same code, except for one instruction cvttss2si vs. cvttsd2si. So it's really using i = (int)d and computing d-(int)d. 0000000000400522 <main>: 400522: 48 83 ec 28 sub $0x28,%rsp 400526: 48 8b 7e 08 mov 0x8(%rsi),%rdi 40052a: ba 0a 00 00 00 mov $0xa,%edx 40052f: be 00 00 00 00 mov $0x0,%esi 400534: e8 17 ff ff ff callq 400450 <strtol@plt> 400539: 89 44 24 1c mov %eax,0x1c(%rsp) 40053d: db 44 24 1c fildl 0x1c(%rsp) 400541: d9 05 89 01 00 00 flds 0x189(%rip) # 4006d0 <_IO_stdin_used+0x38> 400547: dc c9 fmul %st,%st(1) 400549: d9 c9 fxch %st(1) 40054b: d9 54 24 08 fsts 0x8(%rsp) 40054f: dd 5c 24 10 fstpl 0x10(%rsp) 400553: dd 1c 24 fstpl (%rsp) 400556: f2 0f 10 04 24 movsd (%rsp),%xmm0 40055b: bf 9c 06 40 00 mov $0x40069c,%edi 400560: b8 01 00 00 00 mov $0x1,%eax 400565: e8 b6 fe ff ff callq 400420 <printf@plt> 40056a: d9 44 24 08 flds 0x8(%rsp) 40056e: dd 1c 24 fstpl (%rsp) 400571: f2 0f 10 04 24 movsd (%rsp),%xmm0 400576: bf a4 06 40 00 mov $0x4006a4,%edi 40057b: b8 01 00 00 00 mov $0x1,%eax 400580: e8 9b fe ff ff callq 400420 <printf@plt> 400585: d9 44 24 08 flds 0x8(%rsp) 400589: dd 1c 24 fstpl (%rsp) 40058c: f2 0f 10 04 24 movsd (%rsp),%xmm0 400591: bf ac 06 40 00 mov $0x4006ac,%edi 400596: b8 01 00 00 00 mov $0x1,%eax 40059b: e8 80 fe ff ff callq 400420 <printf@plt> * 4005a0: f2 0f 2c 44 24 10 cvttsd2si 0x10(%rsp),%eax *** 4005a6: 89 44 24 1c mov %eax,0x1c(%rsp) 4005aa: db 44 24 1c fildl 0x1c(%rsp) 4005ae: dc 6c 24 10 fsubrl 0x10(%rsp) 4005b2: dd 5c 24 08 fstpl 0x8(%rsp) 4005b6: f2 0f 10 44 24 08 movsd 0x8(%rsp),%xmm0 4005bc: bf b4 06 40 00 mov $0x4006b4,%edi 4005c1: b8 01 00 00 00 mov $0x1,%eax 4005c6: e8 55 fe ff ff callq 400420 <printf@plt> 4005cb: 48 83 c4 28 add $0x28,%rsp 4005cf: c3 retq And btw, it should be easy to fix: $ gcc-5 -O1 -mfpmath=387 -std=c99 -o test test.c && ./test 100 f = 9999999.000000 d = 999999900.000000 g = 999999872.000000 fractional part of d is 0.000000 Andreas