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));
}