Bug 21376 – [x86-only] Returning 32-bit floats have wrong precision

Status
NEW
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Linux
Creation time
2020-11-10T18:03:36Z
Last change time
2024-12-13T19:12:36Z
Keywords
backend, pull, wrong-code
Assigned to
No Owner
Creator
Iain Buclaw
See also
https://issues.dlang.org/show_bug.cgi?id=21581
Moved to GitHub: dmd#17997 →

Comments

Comment #0 by ibuclaw — 2020-11-10T18:03:36Z
Reduced testcase, blocking this PR: https://github.com/dlang/phobos/pull/7669 On x86_64, `log` is given 1.0, but on x86, the value is 0.99999998653882640021551067577298966. --- import core.math; real hypot(real x, real y) { real u = fabs(x); real v = fabs(y); return sqrt(u*u + v*v); } float abs(float re, float im) { return hypot(re, im); } void log(real x) { assert(x == 1); } extern(C) void main() { float re = 0.866025403784438646787; float im = 0.5; return log(abs(re, im)); }
Comment #1 by ibuclaw — 2020-11-10T18:06:15Z
gdc x86 does not have this problem, so it is the dmd compiler emitting wrong code, not the FPU on i686.
Comment #2 by ibuclaw — 2020-11-10T18:18:06Z
Assembly dump of return statement in `float abs()` ----------------------------------------------------- dmd x86: call hypotFeeZe add $0x8,%esp leave ret $0x8 ----------------------------------------------------- dmd x86_64: callq hypotFeeZe add $0x20,%rsp fstpl -0x20(%rbp) movsd -0x20(%rbp),%xmm0 cvtsd2ss %xmm0,%xmm0 leaveq retq ----------------------------------------------------- gdc x86: call hypotFeeZe add $0x18,%esp fstps -0x4(%ebp) flds -0x4(%ebp) leave ret ----------------------------------------------------- gdc x86_64: callq hypotFeeZe add $0x20,%rsp fstps -0xc(%rbp) movss -0xc(%rbp),%xmm0 leaveq retq ----------------------------------------------------- As expected, there is no fstp/fld generated by dmd x86, so the real value returned by hypot is not truncated as per what x86_64 does.
Comment #3 by ibuclaw — 2020-11-10T18:36:03Z
hypot() isn't necessary, so that leaves just the lack of fstp/fld after calling fsqrt. --- import core.math; float abs(float re, float im) { float u = fabs(re); float v = fabs(im); return sqrt(u*u + v*v); } void log(real x) { assert(x == 1); } void main() { float re = 0.866025403784438646787; float im = 0.5; return log(abs(re, im)); }
Comment #4 by ibuclaw — 2020-11-10T18:38:13Z
(In reply to Iain Buclaw from comment #3) > return sqrt(u*u + v*v); ----------------------------------------------------- dmd x86: movss %xmm0,-0x18(%ebp) flds -0x18(%ebp) fmul %st(0),%st movss %xmm2,-0x18(%ebp) flds -0x18(%ebp) fmul %st(0),%st faddp %st,%st(1) fsqrt leave ret $0x8 ----------------------------------------------------- dmd x86_64: movss %xmm0,-0x30(%rbp) flds -0x30(%rbp) fmul %st(0),%st movss %xmm2,-0x30(%rbp) flds -0x30(%rbp) fmul %st(0),%st faddp %st,%st(1) fsqrt fstps -0x30(%rbp) movss -0x30(%rbp),%xmm0 leaveq retq -----------------------------------------------------
Comment #5 by dlang-bot — 2021-01-21T23:12:36Z
@ibuclaw updated dlang/dmd pull request #12073 "fix Issue 21515 extern(C) and extern(C++) returns creal in wrong order" fixing this issue: - fix Issue 21376 - Returning 32-bit floats have wrong precision on i386 https://github.com/dlang/dmd/pull/12073
Comment #6 by ibuclaw — 2021-03-21T09:08:12Z
(In reply to Dlang Bot from comment #5) > @ibuclaw updated dlang/dmd pull request #12073 "fix Issue 21515 extern(C) > and extern(C++) returns creal in wrong order" fixing this issue: > > - fix Issue 21376 - Returning 32-bit floats have wrong precision on i386 > > https://github.com/dlang/dmd/pull/12073 Ignore this, I attempted fixing, but it's all horribly broken.
Comment #7 by robert.schadek — 2024-12-13T19:12:36Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/17997 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB