mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-28 12:05:06 +00:00
Merge pull request #9844 from JJenkx/windows/libc-exp2f-msun
fix(libc): compute exp2f with FreeBSD msun's algorithm, as titles' libc.prx does
This commit is contained in:
3 files changed
+65
-1
No files matched your search
@@ -329,6 +329,49 @@ double APS5_VABI hypot_nid_postfix(double x, double y) {
|
||||
}
|
||||
float APS5_VABI log10f_nid_postfix(float x) { return std::log10(x); }
|
||||
float APS5_VABI logbf_nid_postfix(float x) { return std::logb(x); }
|
||||
float APS5_VABI exp2f_nid_postfix(float x) {
|
||||
static constexpr double exp2ft[16] = {
|
||||
0x1.6a09e667f3bcdp-1, 0x1.7a11473eb0187p-1, 0x1.8ace5422aa0dbp-1, 0x1.9c49182a3f090p-1,
|
||||
0x1.ae89f995ad3adp-1, 0x1.c199bdd85529cp-1, 0x1.d5818dcfba487p-1, 0x1.ea4afa2a490dap-1,
|
||||
0x1.0000000000000p+0, 0x1.0b5586cf9890fp+0, 0x1.172b83c7d517bp+0, 0x1.2387a6e756238p+0,
|
||||
0x1.306fe0a31b715p+0, 0x1.3dea64c123422p+0, 0x1.4bfdad5362a27p+0, 0x1.5ab07dd485429p+0,
|
||||
};
|
||||
static volatile float huge = 0x1p100f;
|
||||
static volatile float twom100 = 0x1p-100f;
|
||||
const float redux = 0x1.8p23f / 16;
|
||||
const float P1 = 0x1.62e430p-1f;
|
||||
const float P2 = 0x1.ebfbe0p-3f;
|
||||
const float P3 = 0x1.c6b348p-5f;
|
||||
const float P4 = 0x1.3b2c9cp-7f;
|
||||
const std::uint32_t hx = std::bit_cast<std::uint32_t>(x);
|
||||
const std::uint32_t ix = hx & 0x7fffffff;
|
||||
if (ix >= 0x43000000) {
|
||||
if (ix >= 0x7f800000) {
|
||||
return (ix & 0x7fffff) != 0 || (hx & 0x80000000) == 0 ? x + x : 0.0f;
|
||||
}
|
||||
if (x >= 0x1.0p7f) {
|
||||
errno = ERANGE;
|
||||
return huge * huge;
|
||||
}
|
||||
if (x <= -0x1.2cp7f) {
|
||||
errno = ERANGE;
|
||||
return twom100 * twom100;
|
||||
}
|
||||
} else if (ix <= 0x33000000) {
|
||||
return 1.0f + x;
|
||||
}
|
||||
volatile float rounded = x + redux;
|
||||
float t = rounded;
|
||||
std::uint32_t i0 = std::bit_cast<std::uint32_t>(t) + 8;
|
||||
const std::int32_t k = static_cast<std::int32_t>(i0 >> 4) << 20;
|
||||
i0 &= 15;
|
||||
t -= redux;
|
||||
const double z = x - t;
|
||||
const double twopk = std::bit_cast<double>(static_cast<std::uint64_t>(static_cast<std::uint32_t>(0x3ff00000 + k)) << 32);
|
||||
const double u = exp2ft[i0] * z;
|
||||
const double tv = exp2ft[i0] + u * (P1 + z * P2) + u * (z * z) * (P3 + z * P4);
|
||||
return static_cast<float>(tv * twopk);
|
||||
}
|
||||
double APS5_VABI exp2_nid_postfix(double x) {
|
||||
int saved_errno = errno;
|
||||
double result = std::exp2(x);
|
||||
@@ -1023,7 +1066,6 @@ double APS5_VABI __powidf2_nid_postfix(double base, int exponent) {
|
||||
return reciprocal ? 1.0 / result : result;
|
||||
}
|
||||
float APS5_VABI expf_nid_postfix(float x) { return std::exp(x); }
|
||||
float APS5_VABI exp2f_nid_postfix(float x) { return std::exp2(x); }
|
||||
float APS5_VABI logf_nid_postfix(float x) {
|
||||
const float ln2_hi = static_cast<float>(6.9313812256e-01);
|
||||
const float ln2_lo = static_cast<float>(9.0580006145e-06);
|
||||
|
||||
@@ -845,6 +845,26 @@ static void CheckExtendedMath() {
|
||||
Require(std::isnan(remainder_nid_postfix(1.0, 0.0)) && std::isnan(remainder_nid_postfix(INFINITY, 1.0)));
|
||||
}
|
||||
|
||||
static void CheckExp2fConsoleBits() {
|
||||
constexpr struct {
|
||||
std::uint32_t input;
|
||||
std::uint32_t expected;
|
||||
int error;
|
||||
} cases[] = {
|
||||
{0x3d00010bu, 0x3f82cd8du, 0}, {0x3f000303u, 0x3fb5066du, 0}, {0x40a0051bu, 0x42000e29u, 0}, {0x42f0070cu, 0x7b813a1bu, 0},
|
||||
{0xbf400909u, 0x3f183437u, 0}, {0xc2f00b14u, 0x037c3073u, 0}, {0x00000000u, 0x3f800000u, 0}, {0x80000000u, 0x3f800000u, 0},
|
||||
{0x33000000u, 0x3f800000u, 0}, {0x3f800000u, 0x40000000u, 0}, {0x42fe0000u, 0x7f000000u, 0}, {0x42ffffffu, 0x7f7fffa7u, 0},
|
||||
{0x43000000u, 0x7f800000u, ERANGE}, {0x7f7fffffu, 0x7f800000u, ERANGE}, {0x7f800000u, 0x7f800000u, 0}, {0xff800000u, 0x00000000u, 0},
|
||||
{0xc2fc0000u, 0x00800000u, 0}, {0xc3150000u, 0x00000001u, 0}, {0xc315ffffu, 0x00000001u, 0}, {0xc3160000u, 0x00000000u, ERANGE},
|
||||
{0xc3160001u, 0x00000000u, ERANGE}, {0xff7fffffu, 0x00000000u, ERANGE}, {0x7fc00001u, 0x7fc00001u, 0}, {0xffc00002u, 0xffc00002u, 0},
|
||||
};
|
||||
for (const auto& item : cases) {
|
||||
errno = 1234;
|
||||
Require(std::bit_cast<std::uint32_t>(exp2f_nid_postfix(std::bit_cast<float>(item.input))) == item.expected);
|
||||
Require(errno == (item.error != 0 ? item.error : 1234));
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckHyperbolic() {
|
||||
const double infinity = std::numeric_limits<double>::infinity();
|
||||
Require(_Cosh_nid_postfix(0.0, 2.0) == 2.0);
|
||||
@@ -1680,6 +1700,7 @@ int main() {
|
||||
CheckHyperbolic();
|
||||
CheckAcoshfMsunBoundaries();
|
||||
CheckCoshfMsunBoundaries();
|
||||
CheckExp2fConsoleBits();
|
||||
CheckScaledHyperbolic();
|
||||
CheckSinhf();
|
||||
CheckAtanhf();
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
- [std::_Throw_Cpp_error](../../../core/libs/prx/libc/src/exception/StandardExceptions.cpp) (libc) follows Dinkumware `thread0.cpp` ([VC12](https://github.com/ganboing/crt.vc12/blob/f1d47126/src/thread0.cpp), [STL](https://github.com/microsoft/STL/blob/da52dc0f/stl/src/thread0.cpp)), without console verification. Codes outside 0..6 throw `std::out_of_range`, the deleting destructor throws, and STREAMS errnos absent from FreeBSD 11.4 [`errno.h`](https://github.com/freebsd/freebsd-src/blob/releng/11.4/sys/sys/errno.h) (`ENODATA`, `ENOSR`, `ENOSTR`, `ETIME`) are omitted. Codes 0..6 throw a 32-byte [VC12 `system_error`](https://github.com/ganboing/crt.vc12/blob/f1d47126/src/system_error) with FreeBSD errnos (16, 22, 3, 12, 1, 11, 35), a static `generic_category` (not `_Generic_object`), and unverified 40-byte [GuestLocale::String](../../../core/libs/prx/libc/include/GuestLocale.hpp) messages from [`syserror.cpp`](https://github.com/ganboing/crt.vc12/blob/f1d47126/src/syserror.cpp)
|
||||
- [Call tracing](../../../core/libs/prx/libc/src/specifics/x86_64/CallTrace.cpp) (`--trace-imports`, `APS5_TRACE_CALLS`) is missing on macOS and records only the entry of a call, not its arguments or result. One process-wide ring keeps the last 65536 calls, so a busy thread pushes the others out; the reporting thread's own calls are listed only while they are still in that ring. Calls are counted per traced target; an import bound to a target already traced under another name is counted under the first name. The thunk saves the integer argument registers and `xmm0` to `xmm7`; wider vector arguments survive only while the recording code avoids AVX, which is untested. Linux has no crash report, so it prints the trace only on `SIGABRT` (guest or host `abort()`), not on `SIGSEGV`; a caller in a module loaded after the last traced import prints without a module name, and a thread aborting while another writes the report waits for it at most 2 seconds
|
||||
- [_Dtest](../../../core/libs/prx/libc/src/Math.cpp) (libc) follows Dinkumware double classification matching _FDtest: finite values return -1, subnormals -2, zeros 0, infinities 1, and NaNs 2.
|
||||
- [exp2f](../../../core/libs/prx/libc/src/Math.cpp) (libc) is FreeBSD msun's [`s_exp2f.c`](https://github.com/freebsd/freebsd-src/blob/release/11.4.0/lib/msun/src/s_exp2f.c), with `huge` and `twom100` read at run time and `x + redux` rounded to float, as msun's `volatile` reads and `STRICT_ASSIGN` do. As in the `libc.prx` that titles ship, `errno` is set to `ERANGE` only in msun's overflow (`x >= 128`) and underflow (`x <= -150`) branches, so a subnormal result leaves it unchanged. Floating-point exceptions are not compared. It gives the same bits and `errno` as the `exp2f` of the `libc.prx` bundled with PPSA07923, PPSA05916 and PPSA13934 for all 2^32 arguments, run on a Windows host.
|
||||
- [app0.zar](../../../core/libs/prx/libc/src/AppArchive.cpp) (libc) - a [ZArchive](https://github.com/Exzap/ZArchive) beside `app0/` is a read-only layer under it: a path missing from `app0/` is looked up in the archive, case-insensitively. It is not a console format; titles ship their files in a PFS image instead. Resolving an archive-only path through any call other than the archive-aware libkernel ones throws, so `fopen`, `stat`, `access`, `opendir` and the rest do not read the archive yet, and `opendir` of a directory that exists in both places, `app0/` itself included, and `fdopen` of an archived descriptor throw instead of missing its entries or reading the null device. A damaged compressed block throws instead of returning `EIO`
|
||||
- [fopen_s](../../../core/libs/prx/libc/src/FileAndHeap.cpp) (libc) - returns the errno of the failed open, as C11 K.3.5.2.1 leaves the nonzero value open and Microsoft's CRT returns errno; the console's Dinkumware `fopen_s` is not verified
|
||||
- [codecvt<wchar_t,char,_Mbstatet> vtable](../../../core/libs/prx/libc/src/LocaleSupport.cpp) (libc, NID `H-TDszhsYuY`) is thirteen zeroed `uintptr_t` slots matching `st_size` 104 on title `libc.prx` from PPSA26344 and on `libSceLibcInternal.sprx` (offset-to-top, typeinfo, two destructors, `_Incref`/`_Decref`, and seven conversion virtuals). Facet calls through the object fault until those methods are wired.
|
||||
|
||||
Reference in new issue
Block a user