feat(libc): implement acosl and frexpl
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
6040a9626e
commit
3cd36b0135
|
|
@ -46,6 +46,12 @@ int APS5_VABI __isinff_nid_postfix(float x) { return std::isinf(x) ? 1 : 0; }
|
|||
double APS5_VABI cbrt_nid_postfix(double x) { return std::cbrt(x); }
|
||||
double APS5_VABI asin_nid_postfix(double x) { return std::asin(x); }
|
||||
double APS5_VABI acos_nid_postfix(double x) { return std::acos(x); }
|
||||
long double APS5_VABI acosl_nid_postfix(long double x) { return std::acos(x); }
|
||||
|
||||
long double APS5_VABI frexpl_nid_postfix(long double x, int* exponent) {
|
||||
if (!std::isfinite(x)) return x;
|
||||
return std::frexp(x, exponent);
|
||||
}
|
||||
double APS5_VABI exp_nid_postfix(double x) { return std::exp(x); }
|
||||
double APS5_VABI atan_nid_postfix(double x) { return std::atan(x); }
|
||||
double APS5_VABI tan_nid_postfix(double x) { return std::tan(x); }
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ std::uint64_t APS5_VABI _Stoul_nid_postfix(const char*, char**, int);
|
|||
std::int64_t APS5_VABI atol_nid_postfix(const char*);
|
||||
long long APS5_VABI atoll_nid_postfix(const char*);
|
||||
int* APS5_VABI __error_nid_postfix();
|
||||
long double APS5_VABI acosl_nid_postfix(long double);
|
||||
long double APS5_VABI frexpl_nid_postfix(long double, int*);
|
||||
struct LibcFloatConstant { std::uint32_t bits[4]; };
|
||||
extern LibcFloatConstant _FInf_nid_postfix;
|
||||
extern LibcFloatConstant _FNan_nid_postfix;
|
||||
|
|
@ -59,6 +61,38 @@ std::lldiv_t APS5_VABI ldiv_nid_postfix(std::int64_t, std::int64_t);
|
|||
}
|
||||
static void Require(bool value) { if (!value) std::abort(); }
|
||||
|
||||
static bool ExtendedBits(long double value, std::uint64_t mantissa, std::uint16_t signExponent) {
|
||||
unsigned char bytes[sizeof(long double)]{};
|
||||
std::memcpy(bytes, &value, sizeof(value));
|
||||
std::uint64_t actualMantissa = 0;
|
||||
std::uint16_t actualSignExponent = 0;
|
||||
std::memcpy(&actualMantissa, bytes, 8);
|
||||
std::memcpy(&actualSignExponent, bytes + 8, 2);
|
||||
return actualMantissa == mantissa && actualSignExponent == signExponent;
|
||||
}
|
||||
|
||||
static void CheckLongDouble() {
|
||||
Require(ExtendedBits(acosl_nid_postfix(-1.0L), 0xc90fdaa22168c235ull, 0x4000));
|
||||
Require(ExtendedBits(acosl_nid_postfix(0.0L), 0xc90fdaa22168c235ull, 0x3fff));
|
||||
Require(ExtendedBits(acosl_nid_postfix(1.0L), 0, 0));
|
||||
Require(std::isnan(acosl_nid_postfix(1.5L)) && std::isnan(acosl_nid_postfix(-2.0L)));
|
||||
|
||||
int exponent = 77;
|
||||
Require(frexpl_nid_postfix(8.0L, &exponent) == 0.5L && exponent == 4);
|
||||
Require(frexpl_nid_postfix(-3.0L, &exponent) == -0.75L && exponent == 2);
|
||||
Require(frexpl_nid_postfix(0.375L, &exponent) == 0.75L && exponent == -1);
|
||||
long double smallest = 0;
|
||||
const std::uint64_t one = 1;
|
||||
std::memcpy(&smallest, &one, sizeof(one));
|
||||
Require(ExtendedBits(frexpl_nid_postfix(smallest, &exponent), 0x8000000000000000ull, 0x3ffe) && exponent == -16444);
|
||||
exponent = 77;
|
||||
Require(ExtendedBits(frexpl_nid_postfix(-0.0L, &exponent), 0, 0x8000) && exponent == 0);
|
||||
exponent = 77;
|
||||
Require(frexpl_nid_postfix(INFINITY, &exponent) == INFINITY && exponent == 77);
|
||||
Require(frexpl_nid_postfix(-INFINITY, &exponent) == -INFINITY && exponent == 77);
|
||||
Require(std::isnan(frexpl_nid_postfix(NAN, &exponent)) && exponent == 77);
|
||||
}
|
||||
|
||||
static void CheckIntegerConversions() {
|
||||
for (const long long numerator : {4294967301LL, -4294967301LL}) {
|
||||
for (const long long denominator : {3LL, -3LL}) {
|
||||
|
|
@ -255,6 +289,7 @@ int main() {
|
|||
Require(std::isnan(logbf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
|
||||
Require(exp2_nid_postfix(-3.) == 0.125);
|
||||
Require(ldexp_nid_postfix(0.75, 4) == 12.);
|
||||
CheckLongDouble();
|
||||
Require(scalbn_nid_postfix(0.75, -2) == 0.1875);
|
||||
Require(scalbnf_nid_postfix(0.75f, 4) == 12.f);
|
||||
Require(nextafterf_nid_postfix(1.f, 2.f) == 0x1.000002p0f && nextafterf_nid_postfix(1.f, 0.f) == 0x1.fffffep-1f);
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [_sceKernelRtldThreadAtexitIncrement, _sceKernelRtldThreadAtexitDecrement](../../core/libs/prx/libkernel/System/src/Rtld.cpp) (libkernel) - the argument is the `dso` address a title's `libc.prx` passes to `__cxa_thread_atexit` (PPSA14632), which fails when Increment returns nonzero. As in the [fpPS4](https://github.com/red-prig/fpPS4) reimplementation, Increment takes a reference on the loaded image containing the address and Decrement releases one; the variants without the leading underscore are assumed to match
|
||||
- [sceImeGetPanelPositionAndForm](../../core/libs/prx/libSceIme/Export.cpp) (libSceIme) - the output is taken to be the `PositionAndForm` that `sceImeDialogGetPanelPositionAndForm` fills; it is never written, since no panel can be open. That a closed panel is reported before a null output is assumed by analogy with `sceImeSetCaret`, not confirmed on a PS5 title
|
||||
- [_sceLibcInternalForceTlsDestructor](../../core/libs/prx/libSceLibcInternal/Export.cpp) (libSceLibcInternal) - behaviour follows `sceLibcForceTlsDestructor(int)` in a title's `libc.prx` (disassembly): the calling thread's destructors whose dso belongs to the module run newest first, only if the dso's module is loaded and the dso points to itself, in up to 4 passes. The return type is unknown (that function returns nothing), 0 is returned. The module of each dso is looked up when the destructors are forced, not when they are registered as `libc.prx` does, and the lookup is Linux only, so on Windows the call throws when the thread has destructors
|
||||
- [acosl](../../core/libs/prx/libc/src/Math.cpp) (libc) - computed by the host's math library, like the other libc math functions here, not by the console's (FreeBSD msun ld80 code in Sony's `libc.prx`): results can differ from the console's in the last bit, and on Linux glibc sets `errno` to `EDOM` for `acosl` outside [-1, 1] where msun only raises the floating-point exception. `long double` is the x87 80-bit format, as Sony's `frexpl` uses it (`fldt 0x8(%rsp)`, result in `st(0)`)
|
||||
- [std_execute_once](../../core/libs/prx/libc/Export.cpp) (libc) - assumed to be the plain-named twin of `std::_Execute_once` (`_ZSt13_Execute_onceRSt9once_flagPFiPvS1_PS1_ES1_`, the callee of Dinkumware `call_once`): it delegates there and gets the [thread.once.callonce] semantics already verified for that symbol (one invocation per flag, concurrent callers block until it completes, and a failing or throwing invocation leaves the flag unready so the next caller runs it). The name equivalence is not confirmed on a title, and the callback convention (called with (null, arg, null), non-zero return meaning success) is the twin's, unverified for this symbol
|
||||
- [Dinkumware mutexes and conditions](../../core/libs/prx/libc/src/Threads.cpp) (libc) use pointer-to-handle arguments, matching the console aerolib signatures reported in [#3079](https://github.com/boykopovar/AnyPS5/pull/3079). The title's `_Mtx_lock` maps `0` to `_Thrd_success` (0), `0x8002000b` to `_Thrd_busy` (3), and other failures to `_Thrd_error` (4); its internal mutex init recognizes recursive flag `0x100`, while every other type uses default attributes. The observed relock failure for a plain mutex suggests those defaults are error-checking, but that has not been confirmed on hardware. The title's `_Mtx_unlock` and `_Cnd_wait` return success regardless of their internal result. The host implementation treats invalid ownership preconditions as no-ops, and throws for invalid handles, host wait errors and destroying a locked mutex as debug guards; those cases are not confirmed against the console.
|
||||
- [tcgetattr, tcsetattr](../../core/libs/prx/libkernel/File/src/Terminal.cpp) (libkernel) - every file and pipe descriptor is taken as not a terminal (`ENOTTY`), and a socket gets `EADDRNOTAVAIL` for `AF_INET` and `EOPNOTSUPP` otherwise, as FreeBSD's `in_control` and `pru_control_notsupp` answer a termios ioctl; what descriptors 0 to 2 of a title are on the console, and whether any of them is a terminal there, is unknown
|
||||
|
|
|
|||
Loading…
Reference in New Issue