Skip to content

fix(libc): set EDOM in fmod and fmodf where titles' libc.prx does - #10345

Open
JJenkx wants to merge 2 commits into
boykopovar:mainfrom
JJenkx:windows/libc-fmod-edom
Open

JJenkx wants to merge 2 commits into
boykopovar:mainfrom
JJenkx:windows/libc-fmod-edom

Conversation

@JJenkx

@JJenkx JJenkx commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What

fmod and fmodf save and restore errno around the host call. #3600 did that for fmod and #9643 for fmodf, both following FreeBSD msun, which never stores errno. #9643's debt entry records that the console's errno was not measured. Measured now, the libc.prx that titles ship sets EDOM exactly where msun's e_fmod.c and e_fmodf.c return (x*y)/(x*y):

  • a zero divisor of either sign;
  • an infinite or NaN dividend;
  • a NaN divisor.

For example, fmod(1, 0) returns 0xfff8000000000000 with EDOM there, fmod(NaN, 2) returns that NaN with EDOM, and fmod(1, inf) returns 1 without errno.

The NaN on that path also differs from the host's:

  • a NaN divisor is returned quieted, even when the dividend is a NaN too;
  • otherwise a NaN dividend is returned quieted;
  • otherwise (zero divisor, infinite dividend) the result is the default NaN (x*y)/(x*y).

UCRT returns the dividend's NaN when both are NaNs, so the host's result differs on 19 of the 4,000,256 double pairs tested below and on 344 of the float ones.

Both functions now take that path themselves and set EDOM; every other argument still goes to the host std::fmod with errno preserved, whose finite results are exact.

Tested

Current-main conflict refresh, 2026-10-27 UTC: exact head 8b4b0ecdfc2fbdb9ae3f10ec929d627cb942fed9 on tested main 74acfad65b3f0fd4eab653f3a3989d298fba1157. Resolved overlapping test/debt context while preserving this branch's authored production/test edits and main's nextafter environment implementation and coverage. Existing prerequisite commits remain in their original series order.

Linux focused rebuild of libc and selected test executables passes guest_math, guest_math_exact, guest_dinkumware_internals, and public_headers, each three times: 12 passes, zero skips. Conventions and whitespace checks pass. Final fetched main cb45ae2ddf6e113a4619e8fed91fe7b9333c5c0f merges cleanly; its later change is an unrelated Windows crash-test pattern, and the executed qualification remains pinned to the stated base. No new Windows, console, GPU, title, full-suite or negative-control run is claimed. Earlier reference/Windows evidence keeps its original pins.

Exact pins, branch patches, preservation proofs, build/test logs, JUnit and lease-push receipts for this refresh batch. SHA-256: e33f98cc467f038af662cc5fa491c3acc1806bb47171cf77b748f0d4d052c1f2; downloaded copy verified.

Latest conflict refresh (2026-10-26): exact head 11d52c9a9f5cdce272b71217031fac5f397bf997 on main bf77a9e9cba4b02c358779b35295176dd9cae164. The conflict was in adjacent debt notes; the production implementations and regression checks are preserved. Main's unrelated _LCosh/_LSinh debt is retained.

Rebuilt libc and the focused test executables on Linux. guest_math, guest_math_exact, guest_dinkumware_internals, and public_headers pass: four groups × three repetitions (12 passes), zero skips. Conventions, whitespace and final main merge checks pass; the source tree is clean. This is a mechanical refresh with a debt-note resolution, so no new console, Windows, title, GPU or negative-control run is claimed. Earlier measurements retain their original exact pins.

Patch/preservation checks, exact pins, build/test logs, JUnit and push receipts. SHA-256: 196fbf4f07b96515f278558ca31d139759c24195adfd35ddebc93f03c186c92b; downloaded copy verified.

Current Linux rebase: 7385e2d9b96eac4c193f74c48cfa5a9a021f0540, one topic commit on main 16ff208dc32cf3927ba1bae492eee363a5ae7ae8, without merge commits. Production and regression function bodies are unchanged from 025a0c21203773de7ae94365aedaffd53beeceec; main's merged log1p implementation, regressions and calls remain intact. Additive regression insertions were retained on both sides.

Fresh Linux x86-64 Release: guest_math, guest_math_exact, guest_dinkumware_internals and public_headers each pass three repeats before and after the production-only main-Math negative control. The negative fails as expected while exact-math/Dinkumware controls pass; restored libc is byte-identical. Conventions and whitespace pass. The Release negative aborts without a named assertion; no more specific failure attribution is claimed.

Fresh exact-head logs, negative/restoration evidence and preservation proof (SHA-256 fba4546fd2ffc5ea33459b5cc498adc8d2844b835d01d33e301b09d530c93087). No new Windows/macOS, title/module matrix or performance result is claimed. Earlier independent reports below retain their original measured revisions.

Previous qualification (historical source pins)

Historical Linux refresh: head 025a0c21203773de7ae94365aedaffd53beeceec, one commit on main 50a4f824fc3ee23177d8e1effbe306e50150187f (no merge commits). Original fmod/fmodf function bodies and CheckFmodConsoleBits are byte-identical; main's expm1 test/function call and other debt entries are retained. The obsolete standalone fmodf debt entry remains removed as reviewed.

Linux 7.2.9 / Ryzen 9 7950X / GCC 16.2.1 / Release: fresh independent libc/math build; guest_math and guest_dinkumware_internals each pass three runs. With only production Math.cpp reverted to this main and the fixture retained, guest_math aborts; restoring the fix gives six passing invocations and the same libc library SHA-256 413501dad82cc3f36177cc0b5e0eb8727289232d67f778a33aef3293acaeae32. No named assertion is emitted by this Release negative control. Conventions and whitespace pass. Windows remains user-paused: the comparison below is historical and has not been rerun on this head.

Exact-head Linux build/test/negative-control receipts, SHA-256 81e2804b8c970b7a9605a8951dd685aeb1525c2976e4e9ac9713cf0ee166301c.

Hosted Build 40151994198 completed successfully on this exact head, including Linux, Windows and both macOS relinker builds. These relinker jobs do not run the libc math regressions; full platform math claims remain scoped to the evidence above/below.

Historical Windows evidence (original implementation):
Windows 11 Enterprise 10.0.22621, Ryzen 9 5950X, WinLibs GCC 15.2.0 UCRT r7, Ninja, Release, BUILD_TESTING=ON, main 65ac1d3.

  • Comparison: a scratch loader runs the decrypted libc.prx of eleven titles natively and supplies __error: PPSA04158, PPSA05916, PPSA07923, PPSA09614, PPSA13934, PPSA20423, PPSA25636, PPSA26528, PPSA33655, PPSA34008 and PPSA35169. It compared their fmod and fmodf with this PR's code on 4,000,256 pairs per title:

    • every pair of 16 special values (±0, subnormals, ±1, 2, DBL_MAX, ±inf, signalling and quiet NaNs of both signs);
    • 4 million random pairs, half random bit patterns and half with the divisor's exponent up to 80 below the dividend's;
    • the float check uses the high 32 bits of each pair.

    All eleven give identical bits and errno for both functions on all of them. EDOM is set on 3,118 of the double pairs and 23,617 of the float pairs. A separate 76-row edge probe (remainder, fmod, remquo, logb, ilogb and nextafter, double and float) prints byte-identical output on all eleven.

  • guest_math: the new CheckFmodConsoleBits has 15 double and 15 float cases with the console's results and errno. They cover each error class with NaN payloads in both positions, a signalling NaN in each position, an infinite divisor, ±0 over ±0, subnormals, and ordinary remainders.

  • Changed tests:

    Their result, FE_INVALID and environment expectations are unchanged and pass. cc @CouchRiv @Noxy-HNR

  • guest_math, guest_floating_point and guest_dinkumware_internals pass in three runs out of three on the exact head.

  • Negative control: with main's Math.cpp and these tests, guest_math aborts, while the other two still pass.

  • A standalone -O0 and -O3 build of the new code with the new vectors, fix(libc): preserve errno across fmodf domain errors #9643's fmodf table and its environment check passes.

  • python tools/check_conventions.py --base origin/main and git diff --check pass.

  • Not tested: Linux and macOS (the error path no longer depends on the host; finite results come from the host's exact fmod), a console, the exception flags against the console, and fmodl.

Independent macOS integration evidence

imellag reports Apple M4 Pro, macOS27.0.1, x86-64 under Rosetta2, using main 61fc572cee plus open macOS build changes. Without this PR, four fmodf domain cases return NaN without FE_INVALID, and guest_math fails at the reported (1,0) case. With this PR's domain expression, plus #9668 and the denormal-operand test adjustment #10907, the reporter gets three passing guest_math runs; omitting this PR restores the failure. The comment does not give this PR's exact tested head, so this is attributed integration evidence, not a new exact-head or title run by us.

Current Linux qualification (2026-10-28)

Rebased onto main 2227f1366188cda5699dd20e2e756a18006a5d4b. Linux CPU validation on 2026-10-28 at 760f4f9386287b626560c16bcbe7363936741872 (Arch Linux 7.2.9, AMD Ryzen 9 7950X, GCC 16.2.1, Ninja Release, BUILD_TESTING=ON).

libc, guest_math_tests and guest_math_exact_tests rebuilt from this exact source. guest_math and guest_math_exact each passed three consecutive runs (6/6, no skips); the same two suites each passed three runs on the pinned main (6/6). Conventions and whitespace checks pass.

Exact source pins, preservation proofs, dependency checks, build logs and JUnit, SHA-256 1176269c9e6948b5252a5db9e660978d7f978fb2d9f4ed6c68bc050b10b5ae68. This is focused Linux CPU qualification; earlier Windows/title/reference measurements retain their original pins. No new title or performance result is claimed.

Current Linux qualification — 2026-10-29

Refreshed against main 5454cd2e455994d992aca39335ce60507eeda1eb.

Linux qualification at 5b596a5d104db3f81d0241afa562fb8726f0c944 (Arch Linux 7.2.9, Ryzen 9 7950X, GCC 16.2.1, Ninja Release, BUILD_TESTING=ON): guest_math, guest_math_exact, guest_dinkumware_internals each pass three consecutive runs (9/9, no skips). The public_headers audit passes at this exact head. All tracked public-header files match the pinned main; the affected test targets rebuild against those headers. Conventions and whitespace checks pass. The same focused groups passed three times on the pinned main.

Evidence: immutable Linux qualification bundle. Its SHA-256 is 53b095da2f67f55b8aa56ba273681e0330fb39739be844458038dde410fb8cc4. No fresh Windows runtime execution is claimed; older measurements retain their recorded source pins.

AI-assisted: yes (Codex).

Additional main-conflict refresh — 2026-10-30

Refreshed to 6215d19689c83c8bd0d33239a341e7394cac215e against tested main de2ba4cecb30ffb1c04d7e7dd693b03eace96b1b. Original authored changes, authorship and main gitlinks are preserved; publication used an exact old-head lease.

The conflict was in debt documentation. Main's newer WebAssembly and license notes are preserved alongside this PR's measured fmod qualification. The production fmod/fmodf bodies and CheckFmodConsoleBits match the previous public head byte for byte; main's other math changes and tests remain. Fresh libc and test builds pass guest_math, guest_math_exact, guest_dinkumware_internals and public_headers three times: 12 executions, zero skips. Earlier reference-library and platform measurements retain their original pins.

Conventions, whitespace and source preservation checks pass. Latest main 42d009f5f37c8f388b01fbfe38d2e704c792c46f has a clean merge preview; that preview tree was not executed. This refresh adds Linux CPU qualification; it adds no Windows/macOS, SDK, GPU, title or performance execution.

Immutable source, build and test receipts, SHA-256 098ecc93f56b576370b295af428157ef9e4b8ae2dabfdcb9816869be02270985 (download verified). AI-assisted: yes (Codex).

Packaging note: the archive's nested result.json retains an earlier packaging digest. The download SHA-256 above is authoritative; all 81 source/test proof files were checked unchanged, including the raw JUnit counts and published-head patches.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source: none
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

AI-assisted (Claude Code).

🤖 Generated with Claude Code

Contributor-reported Windows follow-up: @ycbuzi tested earlier head 11d52c9a9f merged onto main f616a1397f, Windows 11 Home 10.0.26200, WinLibs GCC 15.2.0 UCRT r7, Release. Four groups (guest_math, guest_math_exact, guest_dinkumware_internals, public_headers) each passed three times. Their main-production Math.cpp control aborted guest_math; the other three groups passed. This is an attributed report on that earlier tree, without independently inspected raw logs or an assertion stack; it is not a Windows rerun of subsequent rebased heads. Original report.

@github-actions

github-actions Bot commented Oct 23, 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 11895 core/libs/tests/GuestMath.cpp L2612

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 5303 docs/dev/debt/libc.md
PR 6085 core/libs/prx/libc/src/Math.cpp
PR 6295 core/libs/prx/libc/src/Math.cpp
core/libs/tests/GuestMath.cpp
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 9863 docs/dev/debt/libc.md
PR 10324 docs/dev/debt/libc.md
PR 10405 docs/dev/debt/libc.md
PR 10620 docs/dev/debt/libc.md
PR 10729 docs/dev/debt/libc.md
PR 11332 docs/dev/debt/libc.md
PR 11661 docs/dev/debt/libc.md
PR 11689 docs/dev/debt/libc.md
PR 11698 docs/dev/debt/libc.md
PR 12057 docs/dev/debt/libc.md
PR 12363 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 12965 docs/dev/debt/libc.md

@JJenkx

JJenkx commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Linux run at this PR's exact head 44afb4223f (44afb4223f2fe2b9138fab341b10218be1257391), not merged onto anything else; its base on main is 65ac1d3b50.

Arch Linux, kernel 7.2.9, Ryzen 9 7950X, g++ (GCC) 16.2.1 20260810, glibc 2.44, x86-64. Release, BUILD_TESTING=ON.

  • guest_math: passed in each of 3 runs, exit code 0 each time, with no failed, skipped or not-run tests.

This is the focused test only; no title, console or floating-point exception flags were checked.

AI-assisted: yes (Claude Code).

@harisibrar1 harisibrar1 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.

Checked against main 11d6efa and FreeBSD 11.4 msun e_fmod.c/e_fmodf.c:

  • It still merges cleanly. On main, fmod has moved to Math.cpp:648 and fmodf is at :292, and both still just save and restore errno.
  • The checks in both functions match the msun condition for the (x*y)/(x*y) return (zero divisor, non-finite dividend, NaN divisor), and finite pairs still go to std::fmod with errno preserved.
  • This matches main's fmodl (MathExact.cpp, around lines 91-98), which already sets EDOM and returns (x*y)/(x*y) for the same classes, so all three widths now agree.
  • The debt entry replaces the old fmodf one under Functional, next to the other measured msun entries.

Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 24, 2026
JJenkx pushed a commit to JJenkx/AnyPS5 that referenced this pull request Oct 24, 2026
Additive conflicts with main's newer libc changes: the debt list keeps both
sides' entries (per entry) and GuestMath.cpp keeps both sides' test
functions and calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JJenkx

JJenkx commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Merged current main fe204e1a8d into this branch as 3132cbca3b (was 44afb4223f), a merge commit rather than a rebase. Done on Linux while the Windows session is paused.

  • The conflicts were additive: the docs/dev/debt/libc.md list keeps both sides' entries (checked per entry), and GuestMath.cpp keeps both sides' test functions and calls.
  • New head, Linux only: guest_math and guest_math_exact pass (Arch Linux, kernel 7.2.9, GCC 16.2.1, glibc 2.44, Release, BUILD_TESTING=ON). tools/check_conventions.py --base origin/main reports no errors.
  • Earlier Windows and comparison evidence in this thread stays pinned to the heads it was measured on.

AI-assisted: yes (Claude Code)

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 24, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@JJenkx I checked 3132cbc. The fmod source and regression cases are unchanged, and both the fmod and expm1 test functions and calls are retained. One debt conflict needs a correction: please remove the old standalone fmodf bullet at docs/dev/debt/libc.md:67, as the original patch did. It still says the wrapper preserves errno, which contradicts this PR setting EDOM. Keep the new combined fmod/fmodf entry and the other main entries; the combined entry already records that exception flags remain unverified.

@JJenkx

JJenkx commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

@oneandonlydean thanks, you're right. The merge kept the old standalone fmodf entry that this PR removes; the per-entry merge I used didn't handle entries one side deleted. Fixed in 8bee26992d: that bullet is gone again, and the combined fmod and fmodf entry and main's other entries are unchanged. tools/check_conventions.py --base origin/main passes.

I re-checked the other branches merged the same way for base entries their PR deleted but the merge kept. This was the only one.

AI-assisted: yes (Claude Code)

@JJenkx

JJenkx commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Linux run at this PR's exact head 8bee26992d (8bee26992d127a7fa5b2c3df543188f6fa7883b2), not merged onto anything else; its base on main is fe204e1a8d.

Arch Linux, kernel 7.2.9, Ryzen 9 7950X, g++ (GCC) 16.2.1 20260810, glibc 2.44, x86-64. Release, BUILD_TESTING=ON.

  • guest_math: passed in each of 3 runs, exit code 0 each time, with no failed, skipped or not-run tests.

This is the focused test only; no title, console or floating-point exception flags were checked.

AI-assisted: yes (Claude Code).

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@JJenkx I checked 8bee269. It removes exactly the obsolete standalone fmodf entry, retaining the combined entry and all other debt. The code and test blobs are unchanged. That addresses my request; the remaining step is exact-head CI.

@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 exact head 8bee26992d127a7fa5b2c3df543188f6fa7883b2. The new binary64 and binary32 paths follow the stated FreeBSD msun exceptional-input ordering, set EDOM for zero divisors and invalid operands, preserve incoming errno for finite valid inputs, and leave finite result calculation to std::fmod. The added bit-pattern cases cover signed zero divisors, infinities, quiet/signaling NaNs, payload preference, valid finite results and subnormals. The stale standalone fmodf debt claim is removed; the combined entry records the unverified exception flags.

The author reports guest_math passing three times on this exact head. Hosted eligibility, conventions, Ubuntu/Windows/macOS relinker, ASan, register-context and write-watch checks pass; product Linux/Windows jobs are skipped by policy. I independently ran the conventions check and git diff --check successfully. A local full CMake configure could not complete because the SDL2 submodule has no CMakeLists.txt and the environment lacks SDL XRandR support, so I did not run guest_math locally.

Current #10742 also edits docs/dev/debt/libc.md; combining the heads conflicts only in that document. The code and tests merge cleanly, and the combined debt file should retain both entries. I found no implementation blocker.

@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.

Follow-up to my earlier approval: I refreshed upstream/main and found this branch's merge base is fe204e1a8d3d, with 6,693 current-main commits since it. CONTRIBUTING.md asks contributors to keep branches up to date with main. The local full configure was also blocked, and the available guest_math runs were reported on the older base; the current hosted product jobs are skipped. Please update the branch to current main and rerun guest_math on the resulting tree so the changed fmod implementation and regression cases are validated against the supported base. I will revisit approval after that evidence is available.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@JJenkx
JJenkx force-pushed the windows/libc-fmod-edom branch from 8bee269 to 025a0c2 Compare October 25, 2026 01:47
@JJenkx

JJenkx commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

Refreshed as one commit 025a0c21203773de7ae94365aedaffd53beeceec on main 50a4f824fc3ee23177d8e1effbe306e50150187f, without the previous merge commit. Both fmod functions and the regression fixture are byte-identical to the reviewed implementation. Retained main’s expm1 tests and updated debt entries, and kept the obsolete standalone fmodf debt removed.

Fresh Linux libc/math build passes; guest_math and guest_dinkumware_internals each pass three runs. The production-only main control aborts guest_math; restoration returns both groups to passing and reproduces the positive libc library hash. Conventions/whitespace pass. Description now distinguishes these exact-head checks from historical Windows/bundled-library measurements; no fresh Windows claim.

Logs, JUnit, source/rebase proof and control receipts, SHA-256 81e2804b8c970b7a9605a8951dd685aeb1525c2976e4e9ac9713cf0ee166301c. AI-assisted: Codex.

@imellag

imellag commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

A macOS data point. On Apple M4 Pro, macOS 27.0.1, x86-64 under Rosetta 2, main 61fc572cee plus the open macOS build PRs, Apple's x86-64 libm returns NaN for fmodf(1, 0), fmodf(0, -0), fmodf(inf, 2) and fmodf(1, -0) without raising FE_INVALID. So guest_math fails there without this PR:

Guest fmodf failed for 3f800000 and 00000000: got 7fc00000, invalid 0, errno 73

This PR's (x * y) / (x * y) path raises it, and that check passes. With #9668 (acosf) and a test fix for the x86 denormal-operand flag (#10907) as well, guest_math passes 3 runs out of 3. With #9668 and the test fix but without this PR, it aborts at the line above.

AI-assisted: yes

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@JJenkx
JJenkx force-pushed the windows/libc-fmod-edom branch from 025a0c2 to 7385e2d Compare October 25, 2026 11:14
@JJenkx

JJenkx commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Correction to my refresh note above: that merge of main also moved the SPIRV-Headers, SPIRV-Tools and vorbis submodule pointers back to older commits. A worktree whose submodules were checked out at older commits got staged wholesale. A follow-up commit on top, build: restore submodule pointers to main, puts back main's pointers. This branch's own changes touch no submodules, and its source, tests and debt entries are unchanged.

AI-assisted: yes (Claude Code)

@JJenkx

JJenkx commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Linux run at this PR's exact head ae517dfe1f (ae517dfe1f495ac7c33e5312f2da2b8aab454da1), not merged onto anything else; its base on main is 5bc84038c4.

Arch Linux, kernel 7.2.9, Ryzen 9 7950X, g++ (GCC) 16.2.1 20260810, glibc 2.44, x86-64. Release, BUILD_TESTING=ON.

Passed in each of 3 runs, exit code 0 each time, with no failed, skipped or not-run tests:

  • guest_math

These are the focused tests only; no title or console was used.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Re-checked at the current head ae517dfe1f, after the recent restacks, on Windows (WinLibs GCC 15.2.0 UCRT r7, Release). guest_math passes.

A scratch loader runs the decrypted libc.prx of PPSA07923 and PPSA05916 natively and calls fmod and fmodf by NID next to this build, with 300,000 argument pairs: half random bit patterns, half spread over moderate ranges. Each call compares the result bits and errno. 0 value and 0 errno differences on both titles. Current main (d13b3d7c55) differs on 133 (fmod) and 1,130 (fmodf) errnos against PPSA07923, on the same inputs.

AI-assisted: yes (Claude Code).

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 28, 2026
@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

New head 53966d1832 adds one commit on top of ae517dfe1f: fmod and fmodf now raise FE_INVALID for a NaN argument, as titles' libc.prx does. Values and errno were already exact.

The titles raise FE_INVALID wherever they store EDOM, quiet NaN included, where returning x + x or y + y raised nothing. The domain paths now raise through _Feraise_nid_postfix(0x01).

One existing assertion changed: CheckFmodfErrno on main expects no FE_INVALID for its three quiet-NaN rows, as C specifies (it already expects EDOM for them). PPSA07923's and PPSA13934's libc.prx raise it there, so those rows now expect it. As on #10253, whether to follow the titles or the standard here is the maintainers' call; this follows the titles.

Checks (Windows 11 Enterprise 10.0.22621, WinLibs GCC 15.2.0 UCRT r7, Release; tested at the branch's own head, since it conflicts with main in GuestMath.cpp):

  • 441 special-value pairs against both titles' libc.prx, comparing result bits, errno and FE_INVALID/FE_DIVBYZERO/FE_OVERFLOW/FE_UNDERFLOW: fmod and fmodf go from 80 flag differences each (every pair with a NaN) to 0.
  • Random inputs (PPSA07923): 0 value and 0 errno differences.
  • Tests: guest_math passes in each of 3 runs, and with ae517dfe1f's Math.cpp it fails.

AI-assisted: yes (Claude Code).

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Linux run at this PR's exact head 53966d1832 (53966d183266ddf416075456122c19cfdef7efc3), not merged onto anything else; its base on main is 5bc84038c4.

Arch Linux, kernel 7.2.9, Ryzen 9 7950X, g++ (GCC) 16.2.1 20260810, glibc 2.44, x86-64. Release, BUILD_TESTING=ON, Ninja -j4, private worktree.

  • ctest -R '^guest_math$': passes in each of 3 runs (3 passes).

The branch currently shows as conflicting with main. I did not test a merge.

@JJenkx
JJenkx force-pushed the windows/libc-fmod-edom branch from 53966d1 to 760f4f9 Compare October 28, 2026 12:30
@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main 2227f1366188cda5699dd20e2e756a18006a5d4b. Linux CPU validation on 2026-10-28 at 760f4f9386287b626560c16bcbe7363936741872 (Arch Linux 7.2.9, AMD Ryzen 9 7950X, GCC 16.2.1, Ninja Release, BUILD_TESTING=ON).

libc, guest_math_tests and guest_math_exact_tests rebuilt from this exact source. guest_math and guest_math_exact each passed three consecutive runs (6/6, no skips); the same two suites each passed three runs on the pinned main (6/6). Conventions and whitespace checks pass.

Exact source pins, preservation proofs, dependency checks, build logs and JUnit, SHA-256 1176269c9e6948b5252a5db9e660978d7f978fb2d9f4ed6c68bc050b10b5ae68. This is focused Linux CPU qualification; earlier Windows/title/reference measurements retain their original pins. No new title or performance result is claimed.

AI-assisted: yes.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 28, 2026

@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.

Reviewing exact head 760f4f9386287b626560c16bcbe7363936741872.

What I ran

  • Inspected both commits, the final fmod/fmodf paths and tests, current review discussion, and hosted checks.
  • Confirmed the branch's last tested main was 2227f13661. Current main has added adjacent math and test changes in the same files, but the affected hunks are separate and GitHub reports a clean merge.
  • Hosted conventions, eligibility, labels, register-context, relinker, ASan, write-watch, Windows, and report checks pass. The product Linux job is skipped.
  • I did not run a local build or tests.

Results

Check Result Evidence
Domain/NaN ordering, EDOM and FE_INVALID behavior Reviewed Exact current diff
Linux focused math tests Pass, author-reported guest_math and guest_math_exact, three runs on the tested sync
Windows tests and title-libc comparisons Pass, author-reported Multiple titles and broad input samples; older measured heads
Hosted Windows and supporting platform/policy checks Pass GitHub Actions
Hosted Linux product build Skipped GitHub Actions
Local build and tests Not run This review

Findings

Blocking

None.

Non-blocking

  • The fast bit checks select the same domain cases as the referenced FreeBSD implementation. NaN divisor precedence, NaN dividend handling, zero divisors, and infinite dividends use the measured quiet-NaN/EDOM path; finite results continue through host std::fmod with the prior errno restored.
  • The head documents that finite-result exception flags still come from the host and were not compared with the console. The PR's eleven-title comparisons cover result bits and errno, not console floating-point flags.
  • Main's later adjacent math/test edits remain in separate hunks. Keep them when resolving the resulting textual overlap.

Sources

Not verified

  • I did not locally build or run CTest.
  • Windows title comparisons and Linux focused runs are author-reported; hosted Linux product tests did not run on this PR.

To get this to a good state

No blocking issue remains on the reviewed head. Preserve current main's adjacent math/test changes when merging.

@JJenkx

JJenkx commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

Refreshed against main 5454cd2e455994d992aca39335ce60507eeda1eb.

Linux qualification at 5b596a5d104db3f81d0241afa562fb8726f0c944 (Arch Linux 7.2.9, Ryzen 9 7950X, GCC 16.2.1, Ninja Release, BUILD_TESTING=ON): guest_math, guest_math_exact, guest_dinkumware_internals each pass three consecutive runs (9/9, no skips). The public_headers audit passes at this exact head. All tracked public-header files match the pinned main; the affected test targets rebuild against those headers. Conventions and whitespace checks pass. The same focused groups passed three times on the pinned main.

Evidence: immutable Linux qualification bundle. Its SHA-256 is 53b095da2f67f55b8aa56ba273681e0330fb39739be844458038dde410fb8cc4. No fresh Windows runtime execution is claimed; older measurements retain their recorded source pins.

AI-assisted: yes.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 29, 2026
@blawesom

Copy link
Copy Markdown
Contributor

Static review plus an independent Linux run (CachyOS, kernel 7.2.10, GCC 16.2.1, Ninja, Release, BUILD_TESTING=ON, Ryzen 7 9800X3D). No findings.

What I checked (static)

  • fmod/fmodf gain explicit edge-case handling matching FreeBSD 11.4 e_fmod.c's sentinel return (x*y)/(x*y) with FE_INVALID (raised via _Feraise_nid_postfix(0x01)) before falling back to std::fmod — exactly the case list FreeBSD documents: zero divisor, infinite dividend, NaN dividend, NaN divisor. The divisor-NaN is prioritised over dividend-NaN (returns y+y i.e. quieted divisor), then dividend-NaN (x+x), matching the preference order cited in the debt note ("a NaN divisor is returned quieted, then a NaN dividend, then the default NaN"). Finite arithmetic reuses std::fmod unchanged, preserving the existing errno save/restore around it.
  • The errno contract tightens from 0 to EDOM for NaN/inf/zero-divisor cases (test updates pin the full matrix: EDOM where FreeBSD would set it, sentinel 1234 preserved where it would not). Signaling NaNs (0x7fa00000, 0x7ff4000000000000) are quieted to their default-NaN-QNaN form per the debt-note ordering (expected 0x7ffc0000/0x7fe00000) — that matches the observed console pattern recorded across PPSA04158-PPSA35169 in the note.
  • CheckFmodConsoleBits covers 15 double + 15 float pairs across every edge case class (zero, NaN both signs, inf both signs, sNaN quieting, positive finite remainder). The RestoreFloatingPointState guard in the errno test keeps host FP-env state from leaking, and CheckFmodEdgeFlags runs the pseudo-random cross product of every NaN/inf/zero/sNaN pair asserting all three of isnan, EDOM, FE_INVALID simultaneously.

Focused test run

tree result
this head 5b596a5d10 1/1 guest_math Passed (0.00s)

Not an AGC/shader/VideoOut change — no paired Vulkan-validation run required. The old debt entry is correctly replaced (the "exception flags and NaN payloads remain unverified" note deleted and rewritten to record the 4.0M-sample console-bit comparison that the note now cites — measured, not assumed).

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 30, 2026
JJenkx and others added 2 commits October 30, 2026 08:14
fmod and fmodf preserved errno, following FreeBSD msun, but the libc.prx
of eleven titles sets EDOM exactly where msun returns (x*y)/(x*y): a zero
divisor, an infinite or NaN dividend, or a NaN divisor. There a NaN
divisor is returned quieted, then a NaN dividend, then the default NaN.
Both functions now do the same; finite results still come from the host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Titles' libc.prx raises FE_INVALID wherever fmod and fmodf store EDOM,
a quiet NaN argument included, where returning x + x or y + y raised
nothing. The domain paths now raise through _Feraise, which stores EDOM
and raises the flag in both units. Results and errno are unchanged.
CheckFmodEdgeFlags covers both functions.

CheckFmodfErrno expected no FE_INVALID for its three quiet NaN rows, as
C specifies; PPSA07923's and PPSA13934's libc.prx raise it there, so
those rows now expect it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JJenkx
JJenkx force-pushed the windows/libc-fmod-edom branch from 5b596a5 to 6215d19 Compare October 30, 2026 12:21
@JJenkx

JJenkx commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor Author

Additional main-conflict refresh — 2026-10-30

Refreshed to 6215d19689c83c8bd0d33239a341e7394cac215e against tested main de2ba4cecb30ffb1c04d7e7dd693b03eace96b1b. Original authored changes, authorship and main gitlinks are preserved; publication used an exact old-head lease.

The conflict was in debt documentation. Main's newer WebAssembly and license notes are preserved alongside this PR's measured fmod qualification. The production fmod/fmodf bodies and CheckFmodConsoleBits match the previous public head byte for byte; main's other math changes and tests remain. Fresh libc and test builds pass guest_math, guest_math_exact, guest_dinkumware_internals and public_headers three times: 12 executions, zero skips. Earlier reference-library and platform measurements retain their original pins.

Conventions, whitespace and source preservation checks pass. Latest main 42d009f5f37c8f388b01fbfe38d2e704c792c46f has a clean merge preview; that preview tree was not executed. This refresh adds Linux CPU qualification; it adds no Windows/macOS, SDK, GPU, title or performance execution.

Immutable source, build and test receipts, SHA-256 098ecc93f56b576370b295af428157ef9e4b8ae2dabfdcb9816869be02270985 (download verified). AI-assisted: yes (Codex).

Packaging note: the archive's nested result.json retains an earlier packaging digest. The download SHA-256 above is authoritative; all 81 source/test proof files were checked unchanged, including the raw JUnit counts and published-head patches.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 30, 2026

This branch has not been deployed

No deployments
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