From 31906bf9b0018354976be45d18c06df43707b8c2 Mon Sep 17 00:00:00 2001 From: pushkarreddyy <212133856+pushkarreddyy@users.noreply.github.com> Date: Sun, 11 Oct 2026 12:36:33 +0530 Subject: [PATCH] feat(libc): implement nan and nanf Add standard quiet NaN generators nanf (DZU+K1wozGI) and nan (zck+6bVj5pA) to libc. Resolves startup failure in VLC for PS5 (PPSA85300) where execution halts at nanf on Linux once strsep is available. --- core/libs/prx/libc/src/Math.cpp | 9 +++++++++ core/libs/tests/GuestMath.cpp | 10 ++++++++++ docs/dev/TechnicalDebt.md | 1 + 3 files changed, 20 insertions(+) diff --git a/core/libs/prx/libc/src/Math.cpp b/core/libs/prx/libc/src/Math.cpp index 8bf4d3d6e..259c13735 100644 --- a/core/libs/prx/libc/src/Math.cpp +++ b/core/libs/prx/libc/src/Math.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -125,6 +126,14 @@ int APS5_VABI __isfinite_nid_postfix(double x) { return std::isfinite(x) ? 1 : 0 int APS5_VABI __isnan_nid_postfix(double x) { return std::isnan(x) ? 1 : 0; } int APS5_VABI __isinf_nid_postfix(double x) { return std::isinf(x) ? 1 : 0; } int APS5_VABI __signbit_nid_postfix(double x) { return std::signbit(x) ? 1 : 0; } +float APS5_VABI nanf_nid_postfix(const char* tagp) { + (void)tagp; + return std::bit_cast(0x7fc00000u); +} +double APS5_VABI nan_nid_postfix(const char* tagp) { + (void)tagp; + return std::bit_cast(0x7ff8000000000000ull); +} double APS5_VABI modf_nid_postfix(double x, double* integral) { return std::modf(x, integral); } float APS5_VABI modff_nid_postfix(float x, float* integral) { return std::modf(x, integral); } diff --git a/core/libs/tests/GuestMath.cpp b/core/libs/tests/GuestMath.cpp index 7f668ef75..84ea0db56 100644 --- a/core/libs/tests/GuestMath.cpp +++ b/core/libs/tests/GuestMath.cpp @@ -78,6 +78,8 @@ int APS5_VABI __isinff_nid_postfix(float); int APS5_VABI __isinf_nid_postfix(double); std::lldiv_t APS5_VABI lldiv_nid_postfix(long long, long long); std::lldiv_t APS5_VABI ldiv_nid_postfix(std::int64_t, std::int64_t); +float APS5_VABI nanf_nid_postfix(const char*); +double APS5_VABI nan_nid_postfix(const char*); } static void Require(bool value) { if (!value) std::abort(); } @@ -357,6 +359,14 @@ int main() { Require(fmodf_nid_postfix(-5.5f, 2.f) == -1.5f); Require(std::signbit(fmodf_nid_postfix(-4.f, 2.f))); Require(std::isnan(fmodf_nid_postfix(1.f, 0.f))); + Require(std::bit_cast(nanf_nid_postfix(nullptr)) == 0x7fc00000u); + Require(std::bit_cast(nanf_nid_postfix("")) == 0x7fc00000u); + Require(std::bit_cast(nanf_nid_postfix("123")) == 0x7fc00000u); + Require(!std::signbit(nanf_nid_postfix(""))); + Require(std::bit_cast(nan_nid_postfix(nullptr)) == 0x7ff8000000000000ull); + Require(std::bit_cast(nan_nid_postfix("")) == 0x7ff8000000000000ull); + Require(std::bit_cast(nan_nid_postfix("123")) == 0x7ff8000000000000ull); + Require(!std::signbit(nan_nid_postfix(""))); Require(std::abs(asinf_nid_postfix(0.5f) - 0.5235988f) < 0.000001f); Require(std::abs(acosf_nid_postfix(0.5f) - 1.0471976f) < 0.000001f); Require(std::abs(atan2f_nid_postfix(1.f, -1.f) - 2.3561945f) < 0.000001f); diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index e6360c572..fabec5f7d 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -354,6 +354,7 @@ Throughout the project, every function at every stage either **does exactly what - [/dev/random and /dev/urandom](../../core/libs/prx/libkernel/File/src/RandomDevice.cpp) (libkernel) opened for reading return a descriptor backed by the host null device whose reads are filled from `std::random_device`; both paths behave the same, never block, and positioned reads ignore the offset (FreeBSD `random(4)`). Only the exact paths are recognised, a `dup`ed descriptor reads as an empty file, `fstat`, `lseek`, `mmap` and `select` see the null device, and opening them for writing throws - [Wide-character conversions](../../core/libs/prx/libc/src/Multibyte.cpp) (libc) - The wide `wcsto*` functions parse the ASCII prefix of the guest string, as the C locale accepts only ASCII white space and digits. [`wcsrtombs`](../../core/libs/prx/libc/src/Multibyte.cpp) uses the guest's single-byte C locale through `wcrtomb`; other encodings and shift states are not supported - [realpath](../../core/libs/prx/libc/src/RealPath.cpp) (libc) follows FreeBSD 11's [`realpath.c`](https://github.com/freebsd/freebsd-src/blob/stable/11/lib/libc/stdlib/realpath.c) except for symlinks. The console's guest filesystem has none, so a host symlink under the guest root is followed for existence and type but not expanded, and `..` drops the previous component lexically, as `Resolve` does for every guest path. Through a host link `linkdir -> sub/deep`, `linkdir/../x` gives `x` beside the link, not beside its target. +- [nan and nanf](../../core/libs/prx/libc/src/Math.cpp) (libc) return fixed quiet NaN values (`0x7fc00000` and `0x7ff8000000000000`), ignoring the tag argument as observed in the console's `libc.prx` (both exports load a global constant via `mov rax,[rip+..]; vmovsd xmm0,[rax]; ret`); VLC (PPSA85300) stops on nanf at start-up after strsep. - [SPIRV-Tools optimization](../../core/shader/recompiler/SpirvBackend/src/SpirvOptimizer.cpp) skips CCP and Simplification for modules with storage-only 8- or 16-bit types because the pinned folder produces illegal narrow constants. This also disables unrelated constant folding; the restricted full pipeline mirrors the pinned performance recipe. - [SRT signed comparison](../../core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp) evaluates `SLessThan32` as signed 32-bit less-than, matching the existing SPIR-V backend and [SPIR-V `OpSLessThan`](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpSLessThan). Signed boundary descriptor expressions are tested on the host; native RDNA2/PS5 execution and title behavior remain unverified. - On macOS the [write watch](../../core/libs/prx/libc/src/GuestWriteWatch.cpp) write-protects watched pages and records the first write to each from a SIGBUS/SIGSEGV handler, because macOS has no counterpart to `userfaultfd` write-protect or `MEM_WRITE_WATCH`. The protection is real, so: