Clang folds the constant built by Extended into a normal long double, so
guest_math_exact never fed a pseudo-denormal to __fpclassifyl on macOS.
Keeping the helper out of line makes the value cross the call at run time.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
guest_math_exact did not reach copysignl, sqrtl, lrintl, llrintl, lrintf,
llrintf, scalbf, scalblnf or __isinfl. It now checks copysignl with signed
zeros, sqrtl at -1 and -0, the four lrint forms at +-2.5 under each
rounding mode with errno untouched, scalbf with fractional, infinite and
NaN exponents, scalblnf clamping 64-bit exponents, and __isinfl.
MathExact.cpp was built without -frounding-math, so GCC compiled
std::rint as an add and subtract of 2^52 on the magnitude, which is exact
only when rounding to nearest: under FE_DOWNWARD rint(-1.5) returned -1
and rintf(-1.5f) -1, where C and FreeBSD's libm give -2. lrint and llrint
were right: they call the host libm's llrint, which honours the mode.
MathExact.cpp now builds with -frounding-math. GuestMathExact checks
rint, rintf, rintl, lrint and llrint of -1.5 and 1.5 in all four rounding
modes and that the mode is unchanged.
The failure was first caught by the rounding test of
boykopovar/AnyPS5#2235 (Привалов Александр Владимирович).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
drem, dremf, remainderl and remquol now set EDOM themselves for an
infinite x or a zero y, as fmodl does. Apple's libm never sets errno and
MinGW skips it for long double, so the host could not be relied on.
Guest long is 64 bits, but the host long is 32 bits on Windows. The
lrint, lround and scalbln exports now take and return std::int64_t,
round through llrint and llround, and clamp scalbln exponents to the int
range, where the result is already infinite or zero. The test uses
INT64_MAX instead of LONG_MAX and covers remainderl, dremf and a 2^40
lrint result.
Co-Authored-By: Claude Opus 5.5 <[email protected]>