Skip to content

fix(libc): preserve frexpf decomposition and exception behavior - #11074

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
JJenkx:fix/libc-frexpf-floating-environment
Oct 27, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
JJenkx:fix/libc-frexpf-floating-environment

Conversation

@JJenkx

@JJenkx JJenkx commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

What

The host std::frexp(float) changes signaling-NaN payloads and flags, and ignores the bundled implementation's subnormal scaling and DAZ behavior. frexpf now decomposes the exponent bits, scales only subnormal inputs by2^25, and returns zeros/infinities/NaNs unchanged with exponent0. Normal inputs stay independent of the rounding mode. The implementation is derived from the bundled PPSA03766 function; there is no new export or dependency.

Tested

Linux / GCC16.2.1 / Release, head 7cfbb837c43378e5b2138b1a2cbaee16bdd0d1c5 on main 5949d8bf924b0f3b01c1c4e5e82b2e8ddabd9b97.

  • Three focused CTest groups (guest_math, guest_math_exact, guest_dinkumware_internals), each passing3 repeats before and after the negative control.
  • New960-call regression:20 boundary/special inputs ×4 rounding modes ×4 DAZ/FTZ combinations ×3 sticky-flag seeds. Checks exact result bits, exponent, MXCSR flags/control and guest errno. This includes both signs of zero, subnormals, normal boundaries, maximum finite values, infinity and signaling/quiet NaNs.
  • Broader5633-input differential: 270,384 calls per arm, independently loading the two supplied bundled modules, the candidate, and current-main's function. The candidate matches PPSA03766 in every captured field (result/exponent, SSE and x87 flags/control, errno). Current-main differs in1248 rows, including792 result-bit and408 exponent observations. Inputs combine deterministic random32-bit patterns and every exponent boundary.
  • Both bundled copies agree on all result bits and exponents. PPSA07923's compiler unconditionally scales finite inputs, adding overflow/inexact flags on26,112 large-value rows. The change deliberately follows PPSA03766's conditional scaling; this SDK flag variant and unmasked traps are recorded as debt.
  • Replacing only the new function with current-main's std::frexp fails the committed guest_math regression at the first subnormal's flags. Restoring the implementation passes all repeated groups and produces a byte-identical libc library.

Conventions and whitespace pass. Clean local merge-tree against newer main 6b1f419fefbde12c0fdad3299a294487dc427e44; exact built/tested base remains5949. The overlap scan's45 shared-file cases have no changed frexp/frexpf implementation or callers; #8937 and #10953 have independent additive debt entries at the same location. Retain both rows when reconciling; no functional dependency. Combined branches were not runtime-tested.

Source patch, numeric reference observations, full matrices, regression/negative-control logs and restoration proof — SHA-256 7a75885add6e2691d06ad91fc4d2784fbf54b7a185c1050ce0c2856b634de5e6. The downloaded asset was hash-verified. No proprietary module binaries, extracted instructions or game assets are included.

Windows/macOS, unmasked exceptions and native titles were not tested. No game-unblock, FPS or new-function-count claim.

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
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a (CPU libc only)
  • AI-assisted: yes

@JJenkx

JJenkx commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

Related #11077 corrects double frexp independently of this float fix. The adjacent Math.cpp edits conflict textually, so I tested private combination f014a32788fdd53cb4dac543006d9fbfb8178fdc: both exact implementations, both fixtures/calls and both debt entries retained; all three focused groups pass3 repeats. I then restored the standalone double branch and verified its repeated tests and library SHA. The double PR links the combination patch/logs alongside its separate native-module comparison. No functional dependency or game/FPS claim; I will preserve both functions when refreshing after either lands. AI-assisted: yes.

@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 8937 docs/dev/debt/libc.md L8
PR 10953 docs/dev/debt/libc.md L8

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 6713 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 7648 docs/dev/debt/libc.md
PR 7715 docs/dev/debt/libc.md
PR 8150 docs/dev/debt/libc.md
PR 8417 core/libs/prx/libc/src/Math.cpp
core/libs/tests/GuestMath.cpp
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 9929 docs/dev/debt/libc.md
PR 10324 docs/dev/debt/libc.md
PR 10433 docs/dev/debt/libc.md
PR 10749 docs/dev/debt/libc.md
PR 10989 docs/dev/debt/libc.md
PR 11109 core/libs/prx/libc/src/Math.cpp
core/libs/tests/GuestMath.cpp
docs/dev/debt/libc.md
PR 11332 docs/dev/debt/libc.md
PR 11341 docs/dev/debt/libc.md
PR 11632 core/libs/prx/libc/src/Math.cpp
core/libs/tests/GuestMath.cpp
docs/dev/debt/libc.md
PR 11634 core/libs/prx/libc/src/Math.cpp
core/libs/tests/GuestMath.cpp
docs/dev/debt/libc.md

@wachi35676

Copy link
Copy Markdown
Contributor

Windows/MinGW run, which the description doesn't cover: head 7cfbb837c433 merged onto main 90f918fa7. Windows 11 10.0.26300, WinLibs GCC 15.2.0, Release.

  • guest_math, guest_math_exact and guest_dinkumware_internals pass, 3 runs. That includes the 960-call rounding/DAZ/FTZ/flag regression through the sysv_abi export.
  • With Math.cpp from main, guest_math fails (0xc0000409).
  • I also checked all 2^32 inputs with a probe in GuestMath.cpp. MXCSR was 0x1f80 and the flags were cleared before each call. Finite nonzero inputs must give 0.5 ≤ |r| < 1, the same sign and ldexp(r, e) == x. Zero, inf and NaN must come back bit-identical with exponent 0.
    • This PR: 0 wrong out of 4,294,967,296. Flags are raised only for the 16,777,214 nonzero subnormals, and only DE (0x2), which is what the 2^25 scaling multiply does.
    • Main (host std::frexp, MinGW): 16,777,216 failures, the same as the number of inf/NaN patterns, starting at 0x7f800000. So the exponent-0/bit-identical rule fails there, and 8,388,606 non-subnormal inputs (the count of signaling NaNs) also raise IE.

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

@oneandonlydean oneandonlydean self-assigned this Oct 26, 2026
@oneandonlydean
oneandonlydean merged commit d090e62 into boykopovar:main Oct 27, 2026
18 checks passed
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.

3 participants