Skip to content

feat(libc): implement the compiler-rt floating-point builtins - #6330

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
hypermoist:feat/libc-float-builtins
Oct 18, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
hypermoist:feat/libc-float-builtins

Conversation

@hypermoist

Copy link
Copy Markdown
Contributor

What

Implements the 66 compiler-rt floating-point builtins that the system libc.prx exports and AnyPS5 did not have, in a new src/FloatBuiltins.cpp:

  • arithmetic __add, __sub, __mul, __div (sf3, df3), __neg{s,d}f2
  • comparisons __eq, __ne, __lt, __le, __gt, __ge, __unord (sf2, df2)
  • __extendsfdf2, __truncdfsf2
  • float, double and x87 to 32/64/128-bit integers (__fix*, __fixuns*) and back (__float*, __floatun*)
  • complex __mul{s,d,x}c3, __div{s,d,x}c3, and __powixf2

The console ships an older compiler-rt built with FMA contraction, and these follow that binary (the libc.prx bundled with PPSA08427) rather than current compiler-rt:

  • the soft-float arithmetic and __truncdfsf2 always round to nearest, ignore FTZ/DAZ and raise no exception flags; here the SSE instruction runs under a default MXCSR that is restored afterwards (GNU inline asm, as Math.cpp already uses), and an invalid operation returns the positive quiet NaN compiler-rt returns instead of the SSE default NaN; __sub* negates the second operand first, like compiler-rt, so a NaN subtrahend comes back with its sign flipped
  • __div{s,d}f3 flush a quotient below the smallest normal to a signed zero (old compiler-rt's "Flush denormals to zero")
  • __extendsfdf2 keeps signalling NaNs and copies the payload unshifted; __truncdfsf2 quiets and keeps the low 22 payload bits
  • float-to-integer conversions do not saturate: the significand is shifted by a count masked to the shift width (32, 64 or 128 bits), as the console code does
  • __floatsisf, __floatunsisf and the 128-bit sources round to nearest in integer code; the 64-bit sources use native conversions, which honour MXCSR like the console's cvtsi2s*
  • complex multiplication/division use fma exactly where the console's code fuses, a NaN-skipping maximum like its vmaxss/blend sequence, and scale through the x87 like its scalbn (fscale)
  • __powixf2(x, 1) returns x unchanged

Recorded in docs/dev/debt/libc.md.

Tested

Linux (CachyOS, GCC Release build, plus a clang -Wall -Wextra syntax check): new guest_float_builtins test passes, as do guest_math and guest_crt. tools/check_conventions.py passes; tools/pr_overlap.py --branch reports no overlap.

Differential test against the console: the libc.prx of PPSA08427 was mapped into a Linux process (PT_LOAD segments, RELATIVE relocations, the stack-protector GOT slot pointed at a dummy guard) and each builtin was called side by side with this implementation on 200,000 random and edge-case inputs (NaNs with payloads, infinities, subnormals, boundary exponents), once with the default MXCSR and once with random rounding modes and FTZ/DAZ, comparing result bits and the MXCSR afterwards. All functions agree bit for bit, except:

  • __mul{s,d}c3 and __div{s,d}c3 agree on every value but differ in about 2-6% of cases only in a NaN's payload/sign or in exception flags, because the host fma/logb are not the console's VEX FMA code and libm; noted in the debt entry.
  • __floatundidf could not be run on Linux: it is compiler-rt's assembly with a legacy-SSE orpd on an 8-byte-aligned constant, which faults without AMD's misaligned-SSE mode. It is a correctly rounded conversion and is implemented as a native one.

The harness is not part of this PR because it needs the console binary.

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
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu

Soft-float arithmetic and comparisons, float/double/x87 conversions to and from
32-, 64- and 128-bit integers, __extendsfdf2, __truncdfsf2, complex
multiplication and division and __powixf2, matching the libc.prx bundled with
PPSA08427: soft-float results ignore MXCSR and raise no flags, division flushes
subnormal quotients, NaN payloads are moved unshifted and float-to-integer
conversions do not saturate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
@github-actions

Copy link
Copy Markdown

Progress report (55d2fb6 → f8b611b)

📈 System libraries: 88.91% (+0.2%, +66 implemented functions)

✅ 66 implemented
Library Name
libc __adddf3_nid_postfix
libc __addsf3_nid_postfix
libc __divdc3_nid_postfix
libc __divdf3_nid_postfix
libc __divsc3_nid_postfix
libc __divsf3_nid_postfix
libc __divxc3_nid_postfix
libc __eqdf2_nid_postfix
libc __eqsf2_nid_postfix
libc __extendsfdf2_nid_postfix
libc __fixdfdi_nid_postfix
libc __fixdfsi_nid_postfix
libc __fixdfti_nid_postfix
libc __fixsfdi_nid_postfix
libc __fixsfsi_nid_postfix
libc __fixsfti_nid_postfix
libc __fixunsdfdi_nid_postfix
libc __fixunsdfsi_nid_postfix
libc __fixunsdfti_nid_postfix
libc __fixunssfdi_nid_postfix
libc __fixunssfsi_nid_postfix
libc __fixunssfti_nid_postfix
libc __fixunsxfdi_nid_postfix
libc __fixunsxfsi_nid_postfix
libc __fixunsxfti_nid_postfix
libc __fixxfdi_nid_postfix
libc __fixxfti_nid_postfix
libc __floatdidf_nid_postfix
libc __floatdisf_nid_postfix
libc __floatdixf_nid_postfix
libc __floatsidf_nid_postfix
libc __floatsisf_nid_postfix
libc __floattidf_nid_postfix
libc __floattisf_nid_postfix
libc __floattixf_nid_postfix
libc __floatundidf_nid_postfix
libc __floatundisf_nid_postfix
libc __floatundixf_nid_postfix
libc __floatunsidf_nid_postfix
libc __floatunsisf_nid_postfix
libc __floatuntidf_nid_postfix
libc __floatuntisf_nid_postfix
libc __floatuntixf_nid_postfix
libc __gedf2_nid_postfix
libc __gesf2_nid_postfix
libc __gtdf2_nid_postfix
libc __gtsf2_nid_postfix
libc __ledf2_nid_postfix
libc __lesf2_nid_postfix
libc __ltdf2_nid_postfix
libc __ltsf2_nid_postfix
libc __muldc3_nid_postfix
libc __muldf3_nid_postfix
libc __mulsc3_nid_postfix
libc __mulsf3_nid_postfix
libc __mulxc3_nid_postfix
libc __nedf2_nid_postfix
libc __negdf2_nid_postfix
libc __negsf2_nid_postfix
libc __nesf2_nid_postfix
libc __powixf2_nid_postfix
libc __subdf3_nid_postfix
libc __subsf3_nid_postfix
libc __truncdfsf2_nid_postfix
libc __unorddf2_nid_postfix
libc __unordsf2_nid_postfix

This was referenced Oct 15, 2026
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

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 3987 docs/dev/debt/libc.md
PR 5021 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 5303 docs/dev/debt/libc.md
PR 6044 core/libs/prx/libc/CMakeLists.txt
PR 6226 docs/dev/debt/libc.md
PR 6565 docs/dev/debt/libc.md
PR 7039 docs/dev/debt/libc.md
PR 7081 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7084 core/libs/prx/libc/CMakeLists.txt
PR 7201 core/libs/prx/libc/CMakeLists.txt
PR 7332 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md

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.

2 participants