Skip to content

fix(libc): compute acosl with FreeBSD msun's ld80 code as the bundled libc.prx does - #11260

Merged
adriadam10 merged 6 commits into
boykopovar:mainfrom
AlexFigas:fix/libc-acosl-msun-ld80
Nov 6, 2026
Merged

adriadam10 merged 6 commits into
boykopovar:mainfrom
AlexFigas:fix/libc-acosl-msun-ld80

Conversation

@AlexFigas

@AlexFigas AlexFigas commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What

acosl called the host std::acos. Over 20 million random arguments in (-1, 1), the host result differed from the console's on 1,603,469 of them. This PR replaces it with FreeBSD msun's e_acosl.c (ld80), which is the acosl of the libc.prx that PPSA21564 bundles (0x3e5a0, the library's own code). That binary follows e_acosl.c branch for branch:

  • |x| ≥ 1. For ±1 (exponent 0x3fff, fraction 0) it returns 0 or pi + 2*pio2_lo. For anything else, including the infinities and NaN, it calls _Feraise(1), then returns (x - x) / (x - x). _Feraise (0x11b00) raises FE_INVALID and sets errno to EDOM (0x21).
  • |x| < 0.5. Below exponent 0x3fbe it returns pio2_hi + pio2_lo. Otherwise it returns pio2_hi - (x - (pio2_lo - x*r)), with r = P(x²)/Q(x²).
  • x ≤ -0.5. z = (1 + x) * 0.5, s = fsqrt(z), and the result is pi - 2*(s + (r*s - pio2_lo)).
  • x ≥ 0.5. As above, with df = s whose low 32 mantissa bits are cleared, c = (z - df²)/(s + df), and the result is 2*(df + (r*s + c)).

P, Q, pio2_hi and pio2_lo are the ld80 invtrig.c constants. asinl already reproduces them in Math.cpp (AsinNumerator, AsinDenominator, HalfPiHigh, HalfPiLow), and the binary holds the same 80-bit values. pi is the e_acosl.c constant (0xc90fdaa22168c235:4000 in the binary), and the port reads it from memory as the binary does: as a compile-time constant, GCC loads it with fldpi, which rounds by the current mode, so under round-downward or toward-zero at 64 bits the results below -0.5 and acosl(-1) could come out one bit low (51,708 of 5,000,000 arguments). The port reuses those helpers and adds Pi.

x87 precision. The binary's acosl has no instruction that reads or sets the x87 control word (no fnstcw, fldcw, fldenv or fninit), so it computes at the caller's precision and leaves the control word as it found it. That is the FreeBSD source on amd64: e_acosl.c does not use ENTERI()/RETURNI(), and those are empty outside i386 anyway (math_private.h). The port does the same. One difference had to go: pio2_hi + pio2_lo and pi + 2*pio2_lo are added at run time in the binary, because pio2_hi and pio2_lo are invtrig.c externs, so at 53 bits they round to 53 bits; GCC folded them at 64 bits. The port now adds them through SumAtCallerPrecision, which reads the first half through a volatile. Everything else already ran at run time.

The acosl debt entry keeps what is still open: it runs at the caller's precision, so on a guest thread that starts at 53 bits (the thread-start gap the asinl entry records) it returns the binary's 53-bit result, not the console's 64-bit one; other SDK versions are not compared. The next entry no longer says "as acosl is".

Licence. e_acosl.c's copyright notice is copied verbatim directly above acosl, as Math.cpp already does for the msun code of sinh. Like that copy, it keeps the source's trailing space after "this notice", the only line git diff --check reports.

Tested

On Ubuntu 24.04 under WSL2 (GCC 13.3, Release), head 0de3168, which merges main 813f46c into the previous head 39fb738 (main a4eca2a). The merge has one conflict, in Math.cpp: #12366 rewrote fdim and fdimf right above the host acosl line, so the resolution keeps main's fdim and fdimf, this PR's notice and acosl, and drops the host acosl. 39fb738 resolved a debt-file conflict with #11077's frexp entry; 84502b8 merged main cc26ab4 after a commit that drops the trailing space from the e_acosl.c notice, so git diff --check passes; 8365772 was rebased onto main 2227f13:

Checklist

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the exact head 84591b8434421fdc06a556f585313dc5bd2da4e2. The acosl implementation follows the pinned FreeBSD ld80 algorithm and its tested edge handling; the PR’s reported native comparison covers 20 million random inputs plus boundary cases. I independently checked the diff and conventions in the PR worktree earlier in this sweep; both passed. All hosted eligibility, conventions, intake, report, relinker, register-context and write-watch jobs are now green. Linux and Windows product jobs were skipped, and I did not independently run the native differential here.

I found no blocking issue in the implementation or evidence for this change, so I approve this head.

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

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.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 15802 core/libs/prx/libc/src/Math.cpp L354-357, L363-365, L1019-1024
docs/dev/debt/libc.md L73-75
acosl
PR 15803 core/libs/prx/libc/src/Math.cpp L354-357, L363-365, L1019-1024
docs/dev/debt/libc.md L73-75
acosl
PR 15804 core/libs/prx/libc/src/Math.cpp L354-357, L363-365, L1019-1024
docs/dev/debt/libc.md L73-75
acosl
PR 15807 core/libs/prx/libc/src/Math.cpp L354-357, L363-365, L1019-1024
docs/dev/debt/libc.md L73-75
acosl

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.

Pull request Shared files not compared
PR 5021 docs/dev/debt/libc.md
PR 6295 core/libs/prx/libc/src/Math.cpp
core/libs/tests/GuestMath.cpp
PR 6819 docs/dev/debt/libc.md
PR 7081 docs/dev/debt/libc.md
PR 7386 docs/dev/debt/libc.md
PR 7447 docs/dev/debt/libc.md
PR 7715 docs/dev/debt/libc.md
PR 8150 docs/dev/debt/libc.md
PR 8965 docs/dev/debt/libc.md
PR 9340 docs/dev/debt/libc.md
PR 9371 docs/dev/debt/libc.md
PR 9447 docs/dev/debt/libc.md
PR 9526 docs/dev/debt/libc.md
PR 10780 docs/dev/debt/libc.md
PR 11172 docs/dev/debt/libc.md
PR 11332 docs/dev/debt/libc.md
PR 11724 docs/dev/debt/libc.md
PR 11726 docs/dev/debt/libc.md
PR 11831 docs/dev/debt/libc.md
PR 12518 docs/dev/debt/libc.md
PR 12682 docs/dev/debt/libc.md
PR 12688 docs/dev/debt/libc.md
PR 12700 docs/dev/debt/libc.md
PR 12704 docs/dev/debt/libc.md
PR 12849 docs/dev/debt/libc.md
PR 12965 docs/dev/debt/libc.md
PR 13449 docs/dev/debt/libc.md
PR 13486 core/libs/prx/libc/src/Math.cpp
docs/dev/debt/libc.md
PR 13794 docs/dev/debt/libc.md
PR 13804 docs/dev/debt/libc.md
PR 13809 docs/dev/debt/libc.md
PR 14212 docs/dev/debt/libc.md

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found an x87 precision-state gap while reviewing the follow-on atanl/exp2l ports. This acosl implementation also needs 64-bit x87 precision according to its own debt entry, but it does not scope or restore the x87 control word, and its tests do not run with the 53-bit control setting documented for guest threads (0x27f). FreeBSD's referenced ld80 routine uses ENTERI()/RETURNI() for the computation for this reason; the random comparison under the harness's default environment does not cover callers that arrive with a different precision mode. Please add a scoped precision-control path and a regression that checks the result under 53-bit precision and verifies the original control word is restored, or provide console evidence that the caller's precision mode is intentionally preserved and test both modes. I am updating my earlier approval because this correctness gap affects the stated bit-for-bit behavior. Hosted builds remain skipped for this libc-only path; the comparison and focused test results in the PR are author-reported, not independently rerun here.

@wachi35676

Copy link
Copy Markdown
Contributor

Windows run of head 84591b843442 merged onto main 0f34ebb85, WinLibs GCC 15.2.0, Release. Your runs were under WSL.

  • guest_math passes 3/3. With main's Math.cpp it aborts at Guest acosl failed for 8000000000000000:3fbe.
  • I compared the port with FreeBSD 11.4's e_acosl.c and ld80 invtrig.h. The branches, the BIAS-65 tiny cutoff and the df/c split of the x > 0.5 path match. The only addition is the FE_INVALID/EDOM for |x| > 1, NaN and ∞, which you trace to the binary's _Feraise(1).

AI-assisted: yes (Claude Code); results above were run on this machine.

@AlexFigas

Copy link
Copy Markdown
Contributor Author

@MarcZX10 The console keeps the caller's precision, so I took the second option (evidence and tests at both precisions) rather than forcing 64 bits:

  • The bundled acosl (0x3e5a0) has no instruction that reads or sets the x87 control word: no fnstcw, fldcw, fldenv or fninit. The same holds for atanl (0x417f0), exp2l (0x46a50) and _LLog (0x3fd50). It computes at whatever precision the caller set and leaves the control word as it was.
  • That is msun on amd64. e_acosl.c does not use ENTERI()/RETURNI(), and math_private.h makes them switch to FP_PE only under __i386__; elsewhere they are empty (L335-L362).
  • Run natively with the control word set before each call, the binary gives other bits at 53 bits than at 64. For example, acosl(0.25) is 0xa8b807060a592800:3fff at 53 bits and 0xa8b807060a5927f8:3fff at 64.

Forcing 64 bits would make the export differ from the binary whenever the caller runs at 53 bits. Under AnyPS5, the 53-bit case comes from guest threads not starting with FreeBSD's 0x37f (the gap the asinl entry records). That affects the title's own x87 code as well, so I think the fix belongs at thread start rather than in each libc function.

Changes in ff13b2e:

  • Comparing at 53 bits found one real difference. The binary adds pio2_hi + pio2_lo and pi + 2*pio2_lo at run time, because pio2_hi and pio2_lo are invtrig.c externs, while GCC had folded both at 64 bits. They now go through SumAtCallerPrecision, which reads the first half through a volatile. With that, 20,000,000 random arguments give the binary's bits at 64-, 53- and 24-bit precision.
  • CheckAcosl also runs six arguments at 53 bits through ExtendedBitsAt53Bits. It sets the precision field, calls the export, reads the control word back and restores the caller's. Each result must be the binary's 53-bit one, with the control word left unchanged. With the sums folded again, it aborts at 0x8000000000000000:3fbd. guest_math passes 3 runs on this branch merged into main 5b5d24c.
  • The debt entry now says the function runs at the caller's precision, and what that gives on a 53-bit guest thread.
  • fix(libc): preserve frexp decomposition and exception behavior #11077 goes first: this PR declares Depends on: #11077, and I've noted it there.

@babyhuey

Copy link
Copy Markdown
Contributor

Windows run of this head ff13b2eb6f0, merged onto main 0a570f617d8 (clean merge, local only), with the selection CI's skipped Windows product job uses: Windows 11, Ryzen 7 5800X, RTX 3080, WinLibs GCC 15.2, Release, BUILD_TESTING=ON. The tree was configured fresh after the merge, then select_tests.py select / ninja -f select.ninja selected / --target libs / select_tests.py ctest --parallel 4 --timeout 120.

  • Selected 2547 tests: 1838 pass, 1 fails, guest_raise_exception, which also fails on 0a570f617d8 itself on this machine (crash or timeout under --parallel 4; it passed on 27ad7244d22, and I'm narrowing that down separately), 708 skip. No failures from this PR.

AI-assisted: yes (Claude Code)

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FreeBSD msun port is backed by detailed bitwise comparisons against the bundled libc.prx, across inputs, precisions, rounding modes, errno, and exception flags. The committed known-answer cases also cover the important subnormal and non-canonical paths.

I cannot approve this submitted head against current main. Its merge-base is 68cc9d4, but current main is 3fea2a9. Since that base, main has changed all three paths this PR edits: Math.cpp, GuestMath.cpp, and docs/dev/debt/libc.md. The Tested section names a run on main 5b5d24c, which is not the base of the submitted head, so the report does not establish that this exact diff passed on the integrated tree.

Please rebase the #11077-dependent branch onto current main, resolve the math/debt integration, and rerun guest_math plus the reference comparison on the resulting head. I found no specific arithmetic defect in the inspected cbrtl-adjacent stack code; this request is for current-tree correctness and matching test evidence before approval.

@MarcZX10

Copy link
Copy Markdown
Contributor

Correction to the last sentence of my review: #11260 changes acosl; I mistakenly wrote cbrtl-adjacent. I did not identify a specific arithmetic finding in the portion reviewed, but the current-main rebase and rerun remain necessary before approval.

@maskym

maskym commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Windows result for head ff13b2eb6f, merged into main 1089f2bbfd (the PR's Tested section names no Windows run).

Host: Windows 11 26300, Intel i7-12700K, WinLibs GCC 15.2.0 (x86_64-ucrt-posix-seh, r6), Release, BUILD_TESTING=ON, Ninja. long double is the 80-bit x87 type on this toolchain, as on the console.

The tree also carried the other open libc PRs #11262, #11266, #11632, #11634, #11278, #11270, #11283, #10929, all merged cleanly, so the run is a joint one; the tests of this PR are guest_math. Every test in the set passed: ctest --test-dir build -R "math|libc|...|stdio" 32/32 and ctest -R "guest_dinkumware_internals|guest_standard_streams" 5/5, guest_math in 0.05 s. Build clean. Not run on a PS5.

AI-assisted: yes (Claude Code), the runs and the numbers above are from this machine.

@AlexFigas

Copy link
Copy Markdown
Contributor Author

@MarcZX10 Rebased onto main 1089f2b (23a6c80), and both checks were rerun on that head:

  • guest_math passes 3 runs.
  • The reference comparison now calls acosl_nid_postfix from this head's libc.prx. For 5,000,000 arguments of every kind at each of 64, 53 and 24 bits, under each rounding mode, it gives the binary's result, NaN bits, errno and flags, and leaves the control word unchanged.

The new rounding-mode runs found one difference, now fixed. GCC loaded the pi constant with fldpi, which rounds by the current mode, so under round-downward or toward-zero at 64 bits 51,708 of 5,000,000 results came out one bit low. pi is now read from memory, as the binary does. CheckAcosl checks three such arguments under round-downward, and it fails without the fix.

Depends on: #11077 stays; I'll rebase again when it lands.

@AlexFigas
AlexFigas requested a review from MarcZX10 October 27, 2026 14:51
@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@AlexFigas a survey that may help plan the rest of the ld80 family. I swept every one-argument long double function on main (3a40945e62) against the libc.prx of PPSA07923, loaded natively on Windows 11 and called by NID. The inputs were 200,000 random 80-bit values per function (unit-range, ±100 binades and arbitrary bit patterns), comparing the 80 result bits and errno:

function value differences errno differences open PR
sinl / cosl / tanl 93,845 / 94,083 / 96,835 4 / 4 / 0
acosl 1,358 100,221 #11260
atanl 1,432 0 #11262
expl / exp2l / expm1l 24,719 / 21,442 / 36,515 1,119 / 0 / 1,100 — / #11266 / —
logl / log10l / log2l / log1pl 21,994 / 52,624 / 3,263 / 24,328 0 / 99,883 / 99,839 / 49,969
cbrtl 22,468 0 #11632
sinhl / coshl / tanhl 19,983 / 9,490 / 14,182 4 / 4 / 81,342
asinhl / acoshl / atanhl 35,392 / 11,890 / 14,317 0 / 1 / 0
erfl / erfcl 81,373 / 6,773 90,225 / 45,015
lgammal / tgammal 58,314 / 77,190 29,711 / 29,635

Exact on main: asinl, sqrtl, logbl, floorl, ceill, roundl, truncl, rintl, nearbyintl, fabsl.

Since you're porting this family, I don't want to step on your plans. Which of the uncovered ones are you taking? I could take a separate group, for example logl/log10l/log2l/log1pl, or the hyperbolics, and run the same native comparison on yours. The probe is a small Windows-only harness; I can attach it if useful.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@AlexFigas the two-argument half of the same sweep (PPSA07923, 200,000 random pairs per function):

function value differences errno differences open PR
powl 23,875 60,398 none
atan2l 11,098 0 none
hypotl 5,289 0 your #11634
nextafterl not exported by main #6295

Exact on main: fmodl, remainderl, fdiml, fmaxl, fminl and copysignl. Same question as above for powl and atan2l.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Retracted, see the correction below: the standalone build used here does not reproduce FreeBSD results faithfully.

@AlexFigas one more data point for the planning question, on the log group. I compiled FreeBSD's lib/msun/ld80/s_logl.c standalone with WinLibs GCC 15.2 (x87 control word 0x037f, 64-bit precision) and compared it directly with the titles' logl, log10l, log2l and log1pl. Same 200,000 random 80-bit inputs per function; PPSA07923 and PPSA13934 agree with each other:

source logl log10l log2l log1pl
current main of FreeBSD 905 979 1,032 10,193
revision 5e53a4f90f82 (2017, before the 2021 log2l/log10l change) 905 979 1,032 10,193
the same, built with -DNO_UTAB same counts

Every difference I looked at is 1 ulp, e.g. logl(0xe.45e77cd7eda54e1p+1) is ...272e in the titles and ...272f in FreeBSD. So unlike acosl, atanl and exp2l, which your ports match exactly, the titles' log family doesn't seem to be FreeBSD's s_logl.c as-is: a different algorithm, or a different rounding order in the final hi + lo. A plain port would bring these from 3–52k differences down to about 1k, but not to 0. Just in case it changes which group you start with.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@AlexFigas correction to my s_logl.c comment above: please disregard its conclusion. I validated the same standalone build setup on FreeBSD's ld80/s_exp2l.c, which your #11266 port matches exactly. My standalone build of that file still differs from the titles by 1 ulp on 21,226 of 200,000 ordinary finite arguments, e.g. exp2l(0x9.94bdff4b6d04766p-3). So the 1-ulp differences come from my out-of-tree build (shims for FreeBSD's headers, or the compile setup), not from the titles' source. Whether the titles' log family is FreeBSD's s_logl.c is open. The survey tables against main are unaffected: they compare the titles with this repository's own build, not with my standalone one.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@AlexFigas follow-up on my correction, in case it saves you time on the remaining ld80 files. I found the main reason my standalone FreeBSD build disagreed with the titles. FreeBSD's amd64 math_private.h defines LD80C(m, ex, v) as { .e = (v) }, a full 80-bit constant, but the titles behave as if those constants were rounded to double. Your exp2l port reflects that: its P1 is 0x1.62e42fefa39efp-1.

With LD80C redefined as { .e = (double)(v) }, my standalone build of release/11.4.0 ld80/s_exp2l.c goes from 21,226 differences to 21 of 200,000 against PPSA07923/PPSA13934. The remaining 21 are 1-ulp, which your port avoids, so something smaller still differs in my build. So for the other ld80 files, any LD80C constant probably needs the double-rounded value.

ld80/s_logl.c has no LD80C constants (its polynomial is already double), and the same standalone build still differs there: 905 logl, 979 log10l, 1,032 log2l and 10,193 log1pl. Since my build isn't exact even on exp2l, I can't say whether that's the titles' source or my build. Treat it as unresolved.

AI-assisted: yes (Claude Code).

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed exact current head 8365772e47fbce5df3fda265bd7b194ea2a4e98d. The post-approval delta adds the required e_acosl.c copyright/license notice immediately above the port; it matches FreeBSD release/11.4.0. The reviewed acosl implementation, tests and declared dependency on #11077 remain unchanged. Hosted Ubuntu, Windows, macOS, ASan, register-context and write-watch checks pass; Linux product is skipped by workflow filters. The author reports guest_math and title-binary comparisons on the new heads. No PS5 title run is claimed.

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@AlexFigas this settles the open log question from my correction above, and points at your #11270. Calling the titles' own functions side by side (PPSA07923, 100,000 random 80-bit arguments each), the titles' logl, log10l and log2l are exactly their own _LLog (4iFgTDd9NFs):

titles' function equals titles' _LLog(x, base) with differences
logl base = 0 0 (vs 99,998–100,000 for any other base)
log10l base > 0 (1, 2, 10 all give the same) 0 (vs 99,999 for base < 0)
log2l base < 0 0 (vs 99,997–100,000 for base ≥ 0)

So they're Dinkumware wrappers over _LLog, not FreeBSD's s_logl.c. That explains the 1-ulp gap I couldn't attribute. With your #11270 port of _LLog in place, routing logl/log10l/log2l through it should make all three exact. On main they differ on 21,994, 52,624 and 3,263 of 200,000, with ~100k errno differences for log10l/log2l.

Would you like to add that to #11270, or shall I open it as a small follow-up stacked on #11270 (Depends on: #11270) and run the native comparison on it? Either is fine; I won't start it until you say.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@AlexFigas the same check for the trig and hyperbolic group, in case it helps plan (PPSA07923, 100,000 random 80-bit arguments each). The titles' public functions are exact wrappers over their exported Dinkumware internals:

titles' function equals titles' own differences main's internal vs the titles'
sinl _LSin(x, 0) 0 (_LSin(x, 1): 99,999) 44,499
cosl _LSin(x, 1) 0 44,612
sinhl _LSinh(x, 1.0L) 0 15,827
coshl _LCosh(x, 1.0L) 0 (_LSinh: 77,833) 7,666

So, like logl/log10l/log2l over _LLog, these four reduce to porting _LSin, _LSinh and _LCosh exactly. main's current ports of those internals don't match yet: last column, DinkumwareInternals.cpp:398 and Math.cpp:1963/1983. _LExp is exported too. _LAtan, _LTan and _LHypot are not, which fits your msun ports of atanl and hypotl.

Same offer as before: tell me which of these you'd rather I leave to you.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@AlexFigas one more data point, for prioritising rather than correctness. In the 22 titles of my import audit (converted registries of titles on the share), none imports any of these 25 long double functions:

sinl cosl tanl expl exp2l expm1l logl log10l log2l log1pl powl atan2l sinhl coshl tanhl atanl acosl asinl cbrtl hypotl erfl lgammal tgammal sqrtl fabsl

The same search finds the 8 importers of _FSinh (#12053), so it isn't missing imports in general. It's a sample of 22 titles, so some title surely uses them, but the long double family looks much colder than the double/float one. I'll focus my own time elsewhere; the maps above are there if you continue.

AI-assisted: yes (Claude Code).

@AlexFigas

Copy link
Copy Markdown
Contributor Author

@JJenkx Thanks for the maps. #11270 stays scoped to _LLog. Routing logl, log10l and log2l through it is yours if you want it, as a follow-up with Depends on: #11270. I haven't started any of the other groups (trig, hyperbolic, powl, atan2l, erfl and the gamma functions), so take whichever you like.

@AlexFigas

Copy link
Copy Markdown
Contributor Author

@MarcZX10 Head 84502b8 adds one commit to the approved 8365772 and merges main cc26ab4. The commit drops the trailing space from the e_acosl.c notice (software is freely granted, provided that this notice ), so git diff --check is clean for this PR, as you asked on #12541; nothing else changes. On this head guest_math and guest_math_exact pass 3 runs each, and the 12 console-differential sweeps of acosl (5,000,000 arguments at 64, 53 and 24 bits under each rounding mode) show no difference in result, NaN bits, errno, flags or control word. check_conventions.py passes. The notice stays above the port for now; moving it to the top of Math.cpp conflicts with #11632 and #11634, which add their blocks there, so I'll do it when the dependencies have landed.

@AlexFigas

Copy link
Copy Markdown
Contributor Author

@MarcZX10 Head c6faef7 merges current main e0caf13 into the approved stack; the merge is clean. main now has the write-watch fix (#13220), so the macOS jobs can run again. On this head guest_math and guest_math_exact pass 3 runs each, and the 12 console-differential sweeps of acosl (5,000,000 arguments at 64, 53 and 24 bits under each rounding mode) show no difference in result, NaN bits, errno, flags or control word. git diff --check and check_conventions.py pass. #11262 and #11266 are refreshed on this head.

@AlexFigas

Copy link
Copy Markdown
Contributor Author

@MarcZX10 Head 39fb738 merges current main a4eca2a into the approved branch; nothing else changed. The one conflict was in docs/dev/debt/libc.md: main now has #11077's frexp entry and a host-computed acosl entry above this PR's, so I kept frexp and replaced main's acosl and atanl, sinl, ... entries with this PR's (the latter no longer says "as acosl is"). On this head guest_math and guest_math_exact pass 3 runs each, and the 12 console-differential sweeps of acosl (5,000,000 arguments at 64, 53 and 24 bits under each rounding mode) show no difference in result, NaN bits, errno, flags or control word. git diff --check and check_conventions.py pass. #11077 has merged; Depends on is now #12366 only.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Nov 2, 2026
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ AMD GPU test: passed

PR head 39fb738 merged onto main 1e65852 · tested 2026-11-03 23:31 UTC · 21 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 3,690 passed · 17 failed (0 new, 15 also fail on main, 2 unstable on main) · 61 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 3,768 of 3,818 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (1334 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.2 s, ⚠️ agc_driver_graphics 120.1 s, ⚠️ agc_driver_graphics_maps_fallback 115.5 s, ⚠️ agc_driver_lazy_resolved_abi_switch_set 53.2 s, ⚠️ agc_driver_bda_device 50.9 s
Unstable on main (2, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_graphics: failed in 1 of the last 9 main runs
agc_driver_pipeline_journal: failed in 7 of the last 9 main runs
Failing on main too (15, not counted against this PR)
agc_driver_alpha_to_coverage_sample_mask_export
agc_driver_guest_memory_lifetime_direct
agc_driver_image_table
agc_driver_job_manager_compute_capacity
agc_driver_native_depth_bda_clear
agc_driver_native_depth_buffer_clear
agc_driver_native_depth_clears
agc_driver_native_multisample_depth
agc_driver_store_over_untracked
agc_driver_submit_progress
agc_driver_two_sample_alpha_to_coverage_sample_mask_export
agc_submit_progress
agc_submit_progress_no_timeline
guest_mmap_executable
guest_socket_options_multicast
Passed on retry (1, failed in the parallel run, passed when re-run with a 360 s timeout; not counted against this PR)
agc_driver_dithered_alpha_to_coverage: Timeout in the parallel run; also passed only on retry in 11 other runs in the last 7 days
Validation IDs already present on main (4 IDs in 765 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (765 tests): agc_compute_pipeline_replay, agc_driver, agc_driver_address_passes, agc_driver_address_passes_draw_transitions, agc_driver_address_passes_targets_split, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_alpha_to_coverage_sample_mask_export, and 757 more
VUID-vkCmdCopyImage-srcImage-01548 (9 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store_image_copy, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, and 1 more
VUID-vkCmdCopyImage-srcImage-01551 (9 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store_image_copy, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, and 1 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
Skipped (61)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_copied_writer_label_order_drain: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_float16_unused_nan_payloads: skipped, the device has no native f16 conversions with RTE rounding and kept f16 denormals
agc_driver_image_table_vouched_lookups: skipped, the device reports 4 of 4 host-imported pages written after a GPU read, so a watched imported table cannot be vouched for
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_unit_shadow: skipped, the device does not import watched host memory for unit shadows
agc_driver_unit_shadow_budget: skipped, the device does not import watched host memory for unit shadows
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_idle_publish_wait: skipped, the device reports 4 of 4 host-imported pages written after a GPU read, so a forced watch of the import reads its submissions as CPU stores
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_shadowed_key_stores: skipped, the device imports no watched host memory under a unit shadow
agc_small_tiled_shadow_label: skipped, host imports are unavailable: the test block is not imported and watched
agc_storage_clear_hand_over: skipped, the device imports no watched host memory for the clear-key hand-over
agc_storage_pending_key_refresh: skipped, refreshes over a pending key store are not testable here
agc_unit_shadow: skipped, the device does not import watched host memory for unit shadows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platfo
Reproduce
git fetch origin 39fb738477f0b3f00d41ecc8c4d4066e99ff543a 1e658521a0a599872612bb91949311e2956b5283
git checkout 1e658521a0a599872612bb91949311e2956b5283 && git merge --no-ff 39fb738477f0b3f00d41ecc8c4d4066e99ff543a
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@AlexFigas

Copy link
Copy Markdown
Contributor Author

@MarcZX10 Head 0de3168 merges current main 813f46c into the approved branch. #12366 has merged and rewrote fdim/fdimf right above the old host acosl line, which was the one conflict (in Math.cpp): I kept main's fdim and fdimf, this PR's notice and acosl, and dropped the host acosl. On this head guest_math, guest_math_elementary and guest_math_exact pass 3 runs each, and the 12 console-differential sweeps of acosl (5,000,000 arguments at 64, 53 and 24 bits under each rounding mode) show no difference in result, NaN bits, errno, flags or control word. git diff --check and check_conventions.py pass; Depends on is now none. oberonlift's #15802 stack (opened later) also rewrites the long double functions, so it conflicts with this head; I noted it in the description.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Nov 5, 2026
@adriadam10
adriadam10 merged commit d7e7668 into boykopovar:main Nov 6, 2026
23 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the acosl port against FreeBSD msun's e_acosl.c and the asinl helpers on main, the EDOM/FE_INVALID path, and the x87 precision handling (the bundled binary never touches the control word). CheckAcosl pins exact bits, including cases where the host differs, and fails on main's std::acos, as wachi35676 showed on Windows. Re-reviewed on the current main: the main changes near these lines are in other functions, and the merge is clean. Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants