Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions core/libs/prx/libc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ if(BUILD_TESTING)
set_tests_properties(guest_math PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(guest_float_math_tests ${LIBS_INCLUDE_DIR}/tests/GuestFloatMath.cpp)
target_include_directories(guest_float_math_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_float_math_tests PRIVATE libc)
configure_windows_unwind(guest_float_math_tests)
add_test(NAME guest_float_math COMMAND guest_float_math_tests)
if(WIN32)
set_tests_properties(guest_float_math PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(guest_execute_once_tests ${LIBS_INCLUDE_DIR}/tests/GuestExecuteOnce.cpp)
target_include_directories(guest_execute_once_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_execute_once_tests PRIVATE libc)
Expand Down
15 changes: 15 additions & 0 deletions core/libs/prx/libc/src/Math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ double APS5_VABI hypot_nid_postfix(double x, double y) { return std::hypot(x, y)
float APS5_VABI tanf_nid_postfix(float x) { return std::tan(x); }
float APS5_VABI log10f_nid_postfix(float x) { return std::log10(x); }
float APS5_VABI logbf_nid_postfix(float x) { return std::logb(x); }
double APS5_VABI logb_nid_postfix(double x) { return std::logb(x); }
float APS5_VABI sinhf_nid_postfix(float x) { return std::sinh(x); }
float APS5_VABI nearbyintf_nid_postfix(float x) { return std::nearbyint(x); }
double APS5_VABI exp2_nid_postfix(double x) { return std::exp2(x); }
double APS5_VABI ldexp_nid_postfix(double x, int exponent) { return std::ldexp(x, exponent); }
double APS5_VABI scalbn_nid_postfix(double x, int exponent) { return std::scalbn(x, exponent); }
Expand Down Expand Up @@ -107,6 +110,18 @@ short APS5_VABI _FDtest_nid_postfix(const float* value) {
int APS5_VABI __isnanf_nid_postfix(float x) { return std::isnan(x) ? 1 : 0; }
int APS5_VABI __signbitf_nid_postfix(float x) { return std::signbit(x) ? 1 : 0; }

float APS5_VABI __powisf2_nid_postfix(float base, int exponent) {
const bool reciprocal = exponent < 0;
float result = 1.0f;
while (true) {
if (exponent & 1) result *= base;
exponent /= 2;
if (exponent == 0) break;
base *= base;
}
return reciprocal ? 1.0f / result : result;
}

static std::mutex g_randLock;
static std::uint32_t g_randState = 1;

Expand Down
81 changes: 81 additions & 0 deletions core/libs/tests/GuestFloatMath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cfenv>
#include <cmath>
#include <cstdlib>
#include <initializer_list>
#include <limits>

extern "C" {
double APS5_VABI logb_nid_postfix(double);
float APS5_VABI sinhf_nid_postfix(float);
float APS5_VABI nearbyintf_nid_postfix(float);
float APS5_VABI __powisf2_nid_postfix(float, int);
}

static void Require(bool value) { if (!value) std::abort(); }

static void CheckLogbSinhfNearbyintf() {
const auto infinity = std::numeric_limits<double>::infinity();
Require(logb_nid_postfix(8.) == 3. && logb_nid_postfix(-0.75) == -1.);
Require(logb_nid_postfix(std::numeric_limits<double>::denorm_min()) == -1074.);
Require(logb_nid_postfix(std::numeric_limits<double>::max()) == 1023.);
Require(logb_nid_postfix(0.) == -infinity && logb_nid_postfix(-0.) == -infinity);
Require(logb_nid_postfix(-infinity) == infinity);
Require(std::isnan(logb_nid_postfix(std::numeric_limits<double>::quiet_NaN())));
const auto infinityf = std::numeric_limits<float>::infinity();
Require(sinhf_nid_postfix(0.f) == 0.f && !std::signbit(sinhf_nid_postfix(0.f)));
Require(sinhf_nid_postfix(-0.f) == 0.f && std::signbit(sinhf_nid_postfix(-0.f)));
Require(std::abs(sinhf_nid_postfix(1.f) - 1.1752012f) < 0.000001f);
Require(std::abs(sinhf_nid_postfix(-2.f) + 3.6268604f) < 0.000001f);
Require(sinhf_nid_postfix(100.f) == infinityf && sinhf_nid_postfix(-100.f) == -infinityf);
Require(sinhf_nid_postfix(infinityf) == infinityf && sinhf_nid_postfix(-infinityf) == -infinityf);
Require(std::isnan(sinhf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
std::feclearexcept(FE_ALL_EXCEPT);
Require(nearbyintf_nid_postfix(2.5f) == 2.f && nearbyintf_nid_postfix(3.5f) == 4.f);
Require(nearbyintf_nid_postfix(-2.5f) == -2.f && nearbyintf_nid_postfix(1.4f) == 1.f);
Require(nearbyintf_nid_postfix(-0.4f) == 0.f && std::signbit(nearbyintf_nid_postfix(-0.4f)));
Require(nearbyintf_nid_postfix(8388609.f) == 8388609.f);
Require(std::fetestexcept(FE_INEXACT) == 0);
Require(nearbyintf_nid_postfix(-infinityf) == -infinityf);
Require(std::isnan(nearbyintf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
const int rounding = std::fegetround();
std::fesetround(FE_UPWARD);
Require(nearbyintf_nid_postfix(1.1f) == 2.f && nearbyintf_nid_postfix(-1.9f) == -1.f);
std::fesetround(FE_TOWARDZERO);
Require(nearbyintf_nid_postfix(1.9f) == 1.f && nearbyintf_nid_postfix(-1.9f) == -1.f);
std::fesetround(rounding);
}

static void CheckPowisf2() {
const auto infinity = std::numeric_limits<float>::infinity();
const auto maximum = std::numeric_limits<float>::max();
const auto minimum = std::numeric_limits<int>::min();
Require(__powisf2_nid_postfix(2.f, 0) == 1.f && __powisf2_nid_postfix(0.f, 0) == 1.f);
Require(__powisf2_nid_postfix(std::numeric_limits<float>::quiet_NaN(), 0) == 1.f);
Require(__powisf2_nid_postfix(infinity, 0) == 1.f);
Require(__powisf2_nid_postfix(2.f, 1) == 2.f && __powisf2_nid_postfix(2.f, 10) == 1024.f);
Require(__powisf2_nid_postfix(-2.f, 3) == -8.f && __powisf2_nid_postfix(-2.f, 4) == 16.f);
Require(__powisf2_nid_postfix(2.f, -1) == 0.5f && __powisf2_nid_postfix(2.f, -3) == 0.125f);
Require(__powisf2_nid_postfix(-2.f, -1) == -0.5f);
Require(__powisf2_nid_postfix(0.f, -1) == infinity && __powisf2_nid_postfix(-0.f, -1) == -infinity);
Require(__powisf2_nid_postfix(infinity, -1) == 0.f && __powisf2_nid_postfix(infinity, 3) == infinity);
Require(std::isnan(__powisf2_nid_postfix(std::numeric_limits<float>::quiet_NaN(), 2)));
Require(__powisf2_nid_postfix(1.f, minimum) == 1.f && __powisf2_nid_postfix(-1.f, minimum) == 1.f);
Require(__powisf2_nid_postfix(-1.f, std::numeric_limits<int>::max()) == -1.f);
Require(__powisf2_nid_postfix(2.f, minimum) == 0.f && __powisf2_nid_postfix(0.5f, minimum) == infinity);
Require(__powisf2_nid_postfix(2.f, 127) == 0x1p127f && __powisf2_nid_postfix(2.f, -126) == 0x1p-126f);
Require(__powisf2_nid_postfix(2.f, 128) == infinity);
for (const int exponent : {1, -1}) {
std::feclearexcept(FE_ALL_EXCEPT);
const float result = __powisf2_nid_postfix(maximum, exponent);
Require(result == (exponent == 1 ? maximum : 1.f / maximum));
Require(std::fetestexcept(FE_OVERFLOW) == 0);
}
std::feclearexcept(FE_ALL_EXCEPT);
Require(__powisf2_nid_postfix(0x1p100f, 2) == infinity && std::fetestexcept(FE_OVERFLOW) != 0);
}

int main() {
CheckLogbSinhfNearbyintf();
CheckPowisf2();
}
Loading