Bug 17436 – Weird `cast(double) i != cast(double) i` on 32-bit hosts

Status
RESOLVED
Resolution
WONTFIX
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86
OS
All
Creation time
2017-05-25T23:10:41Z
Last change time
2020-09-07T17:05:58Z
Keywords
backend, wrong-code
Assigned to
No Owner
Creator
kinke

Comments

Comment #0 by kinke — 2017-05-25T23:10:41Z
``` import core.stdc.stdio; void foo(I)(I x) { const equal1 = (cast(double) x == cast(double) x); const f = cast(double) x; const equal2 = (f == x); // f == cast(double) x printf("%a, %a, equal1 = %d, equal2 = %d\n", f, cast(double) x, equal1 ? 1 : 0, equal2 ? 1 : 0); } void main() { foo(long.max); // 2^63-1 rounded up to 2^63 foo(ulong.max); // 2^64-1 rounded up to 2^64 } ``` DMD 2.074 on Windows using `-m32` and `-m32mscoff` as well as on Linux x86 yield something like: 0x1p+63, 0x1p+63, equal1 = 1, equal2 = 0 0x1p+64, 0x1p+64, equal1 = 0, equal2 = 0 [Yep, the inconsistent results for long.max aren't a typo.] With DMD 2.074 on Win64 and Linux x64 and with LDC on all of these platforms we get the expected result: 0x1p+63, 0x1p+63, equal1 = 1, equal2 = 1 0x1p+64, 0x1p+64, equal1 = 1, equal2 = 1 Tracked down while investigating an LDC issue (https://github.com/ldc-developers/ldc/issues/2086).
Comment #1 by bugzilla — 2020-09-04T23:07:16Z
What's happening here is the conversion of ulong.max to double is done by the x87. The computed value is cached in the x87, rather than rounded to double, and reused. Hence, it is different than when stored to an intermediary double and reloaded. This does not occur on 64 bit targets because those do the calculation in 64 bit XMM registers, not the 80 bit x87 registers. The compiler could force a round-to-64 after all operations by writing to memory and then reloading it, but this would be execrably and unacceptably slow. When you need and can afford the load/store, use: https://dlang.org/phobos/core_math.html#.toPrec wontfix
Comment #2 by kinke — 2020-09-07T17:03:28Z
[The generated code uses the ucomisd instruction, which is SSE2, so using cvtsi2sd (SSE2) and avoiding the x87 should be feasible.]
Comment #3 by kinke — 2020-09-07T17:05:58Z
Ah sorry, that's for signed long only.