diff --git a/core/libs/prx/libSceLibcInternal/CMakeLists.txt b/core/libs/prx/libSceLibcInternal/CMakeLists.txt index e5e6092e1..1df68eac3 100644 --- a/core/libs/prx/libSceLibcInternal/CMakeLists.txt +++ b/core/libs/prx/libSceLibcInternal/CMakeLists.txt @@ -95,4 +95,14 @@ if(BUILD_TESTING) set_tests_properties(guest_force_tls_destructor PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(guest_fminf_tests ${LIBS_INCLUDE_DIR}/tests/GuestFminf.cpp) + target_include_directories(guest_fminf_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_fminf_tests PRIVATE libSceLibcInternal libc) + configure_windows_unwind(guest_fminf_tests) + add_test(NAME guest_fminf COMMAND guest_fminf_tests) + set_tests_properties(guest_fminf PROPERTIES TIMEOUT 20) + if(WIN32) + set_tests_properties(guest_fminf PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() endif() diff --git a/core/libs/prx/libSceLibcInternal/Export.cpp b/core/libs/prx/libSceLibcInternal/Export.cpp index 567f6271c..739c8ca5f 100644 --- a/core/libs/prx/libSceLibcInternal/Export.cpp +++ b/core/libs/prx/libSceLibcInternal/Export.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef _WIN32 #include #else @@ -141,4 +142,7 @@ unsigned int APS5_VABI alarm_nid_postfix(unsigned int seconds) { return GuestAlarm_nid_no_patch(seconds); } +float APS5_VABI fminf_nid_postfix(float x, float y) { + return std::fmin(x, y); +} } diff --git a/core/libs/tests/GuestFminf.cpp b/core/libs/tests/GuestFminf.cpp new file mode 100644 index 000000000..75dd90152 --- /dev/null +++ b/core/libs/tests/GuestFminf.cpp @@ -0,0 +1,46 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include +#include + +extern "C" { +float APS5_VABI fminf_nid_postfix(float, float); +} + +static void Check(bool condition, int line) { + if (!condition) { + std::fprintf(stderr, "fminf check failed at line %d\n", line); + std::abort(); + } +} +#define Require(value) Check((value), __LINE__) + +int main() { + const auto nan = std::numeric_limits::quiet_NaN(); + const auto infinity = std::numeric_limits::infinity(); + + Require(fminf_nid_postfix(3.0f, -2.0f) == -2.0f); + Require(fminf_nid_postfix(-2.0f, 3.0f) == -2.0f); + Require(fminf_nid_postfix(1.5f, 2.5f) == 1.5f); + + Require(fminf_nid_postfix(nan, 4.0f) == 4.0f); + Require(fminf_nid_postfix(4.0f, nan) == 4.0f); + Require(std::isnan(fminf_nid_postfix(nan, nan))); + + const auto minNegZero = fminf_nid_postfix(-0.0f, +0.0f); + const auto minPosZero = fminf_nid_postfix(+0.0f, -0.0f); + Require(minNegZero == 0.0f && std::signbit(minNegZero)); + Require(minPosZero == 0.0f && std::signbit(minPosZero)); + Require(std::signbit(fminf_nid_postfix(-0.0f, -0.0f))); + Require(!std::signbit(fminf_nid_postfix(+0.0f, +0.0f))); + + Require(fminf_nid_postfix(infinity, -infinity) == -infinity); + Require(fminf_nid_postfix(-infinity, infinity) == -infinity); + Require(fminf_nid_postfix(infinity, 5.0f) == 5.0f); + Require(fminf_nid_postfix(5.0f, infinity) == 5.0f); + Require(fminf_nid_postfix(-infinity, 5.0f) == -infinity); + Require(fminf_nid_postfix(5.0f, -infinity) == -infinity); + + return 0; +}