Repository navigation
feat(libc): add exact long double and BSD math exports - #6345
Conversation
copysignl, fdiml, fmodl, remainderl, remquol, logbl, ilogbl, rintl, roundl, lroundl, lrintl, llrintl, sqrtl, modfl, nanl, scalblnl, fmal, rint(f), lrint(f), llrint(f), drem(f), scalbln(f), scalb(f), finite(f), __fpclassifyl, __isinfl, __isnanl, __isnormall, _LDtest, _Dclass, _FDclass, _LDclass and _LDsign, matching the libc.prx bundled with PPSA08427 bit for bit, including NaN propagation, errno and FreeBSD fmal special cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
Progress report (9f5d4bd → 1181068)📈 System libraries: 91.8% (+0.08%, +40 implemented functions) ✅ 40 implemented
|
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Title evidence for this PR: Spider-Man: Edge of Time (PPSA99300), added to the homebrew catalog today, stops on Windows 11 10.0.26300, WinLibs GCC 15.2.0 r7, Release.
With this PR it starts, runs its ReXGlue startup and exits by itself with code 0 after reporting the files it needs from the user: That message is the title's own check for the game data it does not ship, so this PR is all it needs to reach it. AI-assisted: yes |
jotitadev
left a comment
There was a problem hiding this comment.
On macOS, drem, dremf and remainderl don't set EDOM. The other paths that the description says set errno (fmodl, remquol) set it explicitly. These three return std::remainder directly, so they rely on the host libm setting errno. glibc does that. Apple's libm never sets errno: math_errhandling is MATH_ERREXCEPT only.
Snippet, macOS 27.2, Apple clang (Xcode 27), M2 Max:
volatile double one = 1.0, zero = 0.0; volatile long double onel = 1.0L, zerol = 0.0L;
errno = 0; std::remainder(one, zero); // errno
errno = 0; std::remainder(onel, zerol); // errno== x86_64 (Rosetta)
math_errhandling=2 (MATH_ERRNO=1)
remainder(1,0)=nan errno=0 (EDOM=33)
remainderf(1,0)=nan errno=0
remainderl(1,0)=nan errno=0
== arm64
(same: errno=0 for all three)
So on a macOS host a guest gets errno == 0 where the console sets EDOM. CheckErrno in GuestMathExact.cpp would also abort at Require(std::isnan(drem_nid_postfix(1.0, 0.0)) && errno == EDOM). The fix would be the same explicit check that remquol already uses (!isnan(x) && !isnan(y) && (isinf(x) || y == 0) → errno = EDOM) in remainderl, drem and dremf. That makes them independent of the host libm.
Not tested: I did not build this PR. libc doesn't build on macOS from main, so this is the host-libm behaviour checked with a standalone snippet. Head 4f608a8.
Written with AI assistance (Claude Code). I ran the check above on my machine.
|
A title that reaches this: Spider-Man: Edge of Time (PPSA99300) from the homebrew catalog, on Linux (Intel Arc, Mesa ANV).
|
adriadam10
left a comment
There was a problem hiding this comment.
Thanks for the thorough differential testing. One thing to fix before merge, already reported by @jotitadev:
drem,dremfandremainderl(MathExact.cpp:83-85,:179-185) returnstd::remainderdirectly, soerrno == EDOMforxinfinite ory == 0depends on the host libm. glibc sets it; Apple's libm (and likely MinGW's) does not, so a guest getserrno == 0where the console setsEDOM, andCheckErrno(GuestMathExact.cpp:71) aborts on those hosts. Use the same explicit check asremquol(!isnan(x) && !isnan(y) && (isinf(x) || y == 0)→errno = EDOM) in all three, and addremainderlanddremfcases to the test.
|
Windows results for this head (4f608a8), merged onto current main without conflicts. Windows 11, WinLibs GCC 15.2.0 r7 (x86_64-ucrt-posix-seh), Release.
Not run: Linux and macOS, and the fix itself. AI-assisted: yes |
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 <noreply@anthropic.com>
What
Adds 40 libc math exports that AnyPS5 did not have, in a new
src/MathExact.cpp. Every one is matched exactly against the console:copysignl,fdiml,fmodl,remainderl,remquol,logbl,ilogbl,rintl,roundl,lroundl,lrintl,llrintl,sqrtl,modfl,nanl,scalblnl,fmalrint(f),lrint(f),llrint(f),drem(f),scalbln(f),scalb(f),finite(f)__fpclassifyl,__isinfl,__isnanl,__isnormall,_LDtest,_Dclass,_FDclass,_LDclass,_LDsignConsole behaviour that is reproduced (found by running the console binary side by side, see Tested):
fdiml,roundl,modfl, andfmalwith a NaNz, return a signalling NaN operand unquieted;rint/rintfquiet it.nanlignores its argument and always returns the default quiet NaN.fmodlsetsEDOMwheneverxis infinite or NaN,yis zero oryis NaN (NaN inputs included);remquol,remainderlanddrem(f)set it only for real domain errors.scalb(f)never touches errno.remquolreports the quotient modulo 8 with its sign (glibc can report ±8 where the console reports 0).ilogbl(NaN)isINT_MAX;scalblnltruncates its exponent toint(scalblnl(1, 2^32 + 1) == 2).fmalis FreeBSD's:x*y + zwhenxoryis zero or non-finite,x*ywhenzis zero,zwhen onlyzis non-finite, andx*ywhenzis more than 128 binades below the product (so a midpoint product rounds to even instead of usingz's sign).__fpclassifylreturns the Dinkumware codes (-2 denormal, -1 finite, 0 zero, 1 infinite, 2 NaN), like_LDtest; they differ only on pseudo-denormals, which_LDtesttreats as finite._LDsignreturns the raw sign bit (-32768).Two known gaps are recorded in
docs/dev/debt/libc.md:remquolleaves*quounchanged when the result is NaN (the console stores a value that depends on earlier x87 state), and non-canonical 80-bit encodings passed to the arithmetic functions follow the host x87.Tested
Linux (CachyOS, GCC Release build, plus a clang
-Wall -Wextrasyntax check): newguest_math_exacttest and the fullctestsuite pass.tools/check_conventions.pypasses;tools/pr_overlap.py --branchreports no line overlap.Differential test against the console: the PPSA08427
libc.prxwas mapped into a Linux process (its__errorimport bound to the test's errno) and all 40 functions were run side by side with this implementation on 200,000 random inputs each (random exponents and mantissas, signalling and quiet NaNs with payloads, infinities, zeros, subnormals, hugelongexponents). Results agree bit for bit, and errno agrees, everywhere except theremquolNaN quotient noted above. All 40 NIDs are also exported by a newerlibc.prxbuild (J03848509).Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code
https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu