From 6fd6e9c306e35bac0225292854fd4c481797f567 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Wed, 21 Aug 2024 22:40:58 +0300 Subject: [PATCH] [COMPILER_APITEST] Add tests for float to int conversion These tests come with a VS solution, because that is the only way to test against a known good system, as the required runtime functions (like _ftol) are statically linked from the VS runtime library. --- .../rostests/apitests/compiler/CMakeLists.txt | 1 + .../apitests/compiler/compiler_apitest.sln | 31 ++ .../compiler/compiler_apitest.vcxproj | 93 ++++++ .../rostests/apitests/compiler/floatconv.c | 277 ++++++++++++++++++ modules/rostests/apitests/compiler/testlist.c | 4 + 5 files changed, 406 insertions(+) create mode 100644 modules/rostests/apitests/compiler/compiler_apitest.sln create mode 100644 modules/rostests/apitests/compiler/compiler_apitest.vcxproj create mode 100644 modules/rostests/apitests/compiler/floatconv.c diff --git a/modules/rostests/apitests/compiler/CMakeLists.txt b/modules/rostests/apitests/compiler/CMakeLists.txt index 163a0220c03..f43a47600a8 100644 --- a/modules/rostests/apitests/compiler/CMakeLists.txt +++ b/modules/rostests/apitests/compiler/CMakeLists.txt @@ -6,6 +6,7 @@ if (MSVC OR ARCH STREQUAL "i386") endif() list(APPEND SOURCE + floatconv.c pseh.c pseh_cpp.cpp psehtest2.c diff --git a/modules/rostests/apitests/compiler/compiler_apitest.sln b/modules/rostests/apitests/compiler/compiler_apitest.sln new file mode 100644 index 00000000000..819d3e90633 --- /dev/null +++ b/modules/rostests/apitests/compiler/compiler_apitest.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35219.272 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compiler_apitest", "compiler_apitest.vcxproj", "{CBB00980-3B4F-4006-973E-61B462D057B3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CBB00980-3B4F-4006-973E-61B462D057B3}.Debug|x64.ActiveCfg = Debug|x64 + {CBB00980-3B4F-4006-973E-61B462D057B3}.Debug|x64.Build.0 = Debug|x64 + {CBB00980-3B4F-4006-973E-61B462D057B3}.Debug|x86.ActiveCfg = Debug|Win32 + {CBB00980-3B4F-4006-973E-61B462D057B3}.Debug|x86.Build.0 = Debug|Win32 + {CBB00980-3B4F-4006-973E-61B462D057B3}.Release|x64.ActiveCfg = Release|x64 + {CBB00980-3B4F-4006-973E-61B462D057B3}.Release|x64.Build.0 = Release|x64 + {CBB00980-3B4F-4006-973E-61B462D057B3}.Release|x86.ActiveCfg = Release|Win32 + {CBB00980-3B4F-4006-973E-61B462D057B3}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F64379E4-70F2-4E62-90BC-00B1308C96D4} + EndGlobalSection +EndGlobal diff --git a/modules/rostests/apitests/compiler/compiler_apitest.vcxproj b/modules/rostests/apitests/compiler/compiler_apitest.vcxproj new file mode 100644 index 00000000000..fa0fc6bd34f --- /dev/null +++ b/modules/rostests/apitests/compiler/compiler_apitest.vcxproj @@ -0,0 +1,93 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {cbb00980-3b4f-4006-973e-61b462d057b3} + compilerapitest + 10.0 + + + + Application + Unicode + v142 + + + true + + + false + true + + + + + + + + + Level3 + true + true + $(ProjectDir)..\include;$(ProjectDir)..\..\..\..\sdk\include\reactos;$(ProjectDir)..\..\..\..\sdk\lib\pseh\include;%(AdditionalIncludeDirectories) + _CONSOLE;__VS_PROJECT__;%(PreprocessorDefinitions) + 4532;4996 + + + Console + true + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + true + true + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + _X86_;WIN32;%(PreprocessorDefinitions) + + + + + _AMD64_;%(PreprocessorDefinitions) + + + + + + + + + + \ No newline at end of file diff --git a/modules/rostests/apitests/compiler/floatconv.c b/modules/rostests/apitests/compiler/floatconv.c new file mode 100644 index 00000000000..195c587b60b --- /dev/null +++ b/modules/rostests/apitests/compiler/floatconv.c @@ -0,0 +1,277 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Test for floating point conversion + * COPYRIGHT: Copyright 2024 Timo Kreuzer + */ + +#include + +/* Note: There are 2 behaviors for float to unsigned integer conversion: + * 1. The old behavior, which exists only on x86 and CL versions up to somewhere + * between 19.40.33811 and 19.41.33923: + * - If a negative float is cast to an unsigned integer, the result is ULONG_MAX + * for uint32 and ULLONG_MAX for uint64. + * - If a float is cast to an unsigned long and the value is larger than ULONG_MAX, + * the result is ULONG_MAX. + * 2. The new behavior (all x64 and x86 versions after the ones mentioned above): + * - If a negative float is cast to an unsigned integer, the result is the same as + first casting to the signed type, then casting to the unsigned type. + * - If a float is cast to an unsigned integer and the value is too large for the type, + * the result is 0 for uint32 and 0x8000000000000000 for uint64. + * In the old version, the float to unsigned conversion was inlined and used _ftoul2 and + * a comparison against 0x43e0000000000000 (9223372036854775808.0) to check for overflow. + * In the new version, the float to unsigned conversion is done by a call to _ftoul2_legacy, + * which checks for overflow by comparing against 0x5f800000 (18446744073709551616.0) and + * then forwards the call to either _ftol2 or _ftoul2. + */ + +#if defined(_M_IX86) && defined(__VS_PROJECT__) && (_MSC_FULL_VER < 194133923) +#define OLD_BEHAVIOR +#endif + +#ifdef OLD_BEHAVIOR +#define ULONG_OVERFLOW ULONG_MAX +#define ULONGLONG_OVERFLOW ULLONG_MAX +#else +#define ULONG_OVERFLOW 0ul +#define ULONGLONG_OVERFLOW 0x8000000000000000ull +#endif + +#ifdef __GNUC__ +#define todo_gcc todo_ros +#else +#define todo_gcc +#endif + +__declspec(noinline) +long cast_float_to_long(float f) +{ + return (long)f; +} + +__declspec(noinline) +unsigned long cast_float_to_ulong(float f) +{ + return (unsigned long)f; +} + +__declspec(noinline) +long cast_double_to_long(double d) +{ + return (long)d; +} + +__declspec(noinline) +unsigned long cast_double_to_ulong(double d) +{ + return (unsigned long)d; +} + +__declspec(noinline) +long long cast_float_to_longlong(float f) +{ + return (long long)f; +} + +__declspec(noinline) +unsigned long long cast_float_to_ulonglong(float f) +{ + return (unsigned long long)f; +} + +__declspec(noinline) +long long cast_double_to_longlong(double d) +{ + return (long long)d; +} + +__declspec(noinline) +unsigned long long cast_double_to_ulonglong(double d) +{ + return (unsigned long long)d; +} + +void Test_float(void) +{ + // float to long cast + ok_eq_long(cast_float_to_long(0.0f), 0l); + ok_eq_long(cast_float_to_long(1.0f), 1l); + ok_eq_long(cast_float_to_long(-1.0f), -1l); + ok_eq_long(cast_float_to_long(0.5f), 0l); + ok_eq_long(cast_float_to_long(-0.5f), 0l); + ok_eq_long(cast_float_to_long(0.999999f), 0l); + ok_eq_long(cast_float_to_long(-0.999999f), 0l); + ok_eq_long(cast_float_to_long(2147483500.0f), 2147483520l); + ok_eq_long(cast_float_to_long(2147483583.999f), 2147483520l); + ok_eq_long(cast_float_to_long(-2147483583.999f), -2147483520l); + ok_eq_long(cast_float_to_long(2147483584.0f), LONG_MIN); // -2147483648 + ok_eq_long(cast_float_to_long(2147483648.0f), LONG_MIN); // -2147483648 + ok_eq_long(cast_float_to_long(-2147483648.0f), LONG_MIN); // -2147483648 + ok_eq_long(cast_float_to_long(10000000000.0f), LONG_MIN); + ok_eq_long(cast_float_to_long(-10000000000.0f), LONG_MIN); + + // float to unsigned long cast (positive values) + ok_eq_ulong(cast_float_to_ulong(0.0f), 0ul); + ok_eq_ulong(cast_float_to_ulong(1.0f), 1ul); + ok_eq_ulong(cast_float_to_ulong(0.5f), 0ul); + ok_eq_ulong(cast_float_to_ulong(0.999999f), 0ul); + ok_eq_ulong(cast_float_to_ulong(2147483648.0f), 2147483648ul); // 0x80000000 + ok_eq_ulong(cast_float_to_ulong(4294967150.0f), 4294967040ul); // 0xFFFFFF00 + ok_eq_ulong(cast_float_to_ulong(4294967294.0f), ULONG_OVERFLOW); + + // float to unsigned long cast (negative values) + ok_eq_ulong(cast_float_to_ulong(-0.0f), 0ul); + ok_eq_ulong(cast_float_to_ulong(-0.5f), 0ul); + ok_eq_ulong(cast_float_to_ulong(-1.0f), ULONG_MAX); +#ifdef OLD_BEHAVIOR + ok_eq_ulong(cast_float_to_ulong(-10.0f), ULONG_MAX); + ok_eq_ulong(cast_float_to_ulong(-1147483648.0f), ULONG_MAX); + ok_eq_ulong(cast_float_to_ulong(-2147483648.0f), ULONG_MAX); +#else + ok_eq_ulong(cast_float_to_ulong(-10.0f), (unsigned long)-10); + ok_eq_ulong(cast_float_to_ulong(-1147483648.0f), (unsigned long)-1147483648ll); + ok_eq_ulong(cast_float_to_ulong(-2147483648.0f), (unsigned long)-2147483648ll); +#endif + + // float to long long cast + ok_eq_longlong(cast_float_to_longlong(0.0f), 0ll); + ok_eq_longlong(cast_float_to_longlong(1.0f), 1ll); + ok_eq_longlong(cast_float_to_longlong(-1.0f), -1ll); + ok_eq_longlong(cast_float_to_longlong(0.5f), 0ll); + ok_eq_longlong(cast_float_to_longlong(-0.5f), 0ll); + ok_eq_longlong(cast_float_to_longlong(0.999999f), 0ll); + ok_eq_longlong(cast_float_to_longlong(-0.999999f), 0ll); + ok_eq_longlong(cast_float_to_longlong(9223371761976868863.9999f), 9223371487098961920ll); + ok_eq_longlong(cast_float_to_longlong(9223371761976868864.0f), LLONG_MIN); + ok_eq_longlong(cast_float_to_longlong(-9223371761976868863.9999f), -9223371487098961920ll); + ok_eq_longlong(cast_float_to_longlong(-9223371761976868864.0f), LLONG_MIN); + ok_eq_longlong(cast_float_to_longlong(100000000000000000000.0f), LLONG_MIN); + ok_eq_longlong(cast_float_to_longlong(-100000000000000000000.0f), LLONG_MIN); + + // float to unsigned long long cast (positive values) + ok_eq_ulonglong(cast_float_to_ulonglong(0.0f), 0ull); + ok_eq_ulonglong(cast_float_to_ulonglong(1.0f), 1ull); + ok_eq_ulonglong(cast_float_to_ulonglong(0.5f), 0ull); + ok_eq_ulonglong(cast_float_to_ulonglong(0.999999f), 0ull); + ok_eq_ulonglong(cast_float_to_ulonglong(9223371487098961920.0f), 9223371487098961920ull); // 0x7FFFFF8000000000 + ok_eq_ulonglong(cast_float_to_ulonglong(9223372036854775808.0f), 9223372036854775808ull); // 0x8000000000000000 + ok_eq_ulonglong(cast_float_to_ulonglong(18446743523953737727.9f), 18446742974197923840ull); // 0xFFFFFF0000000000 + todo_gcc ok_eq_ulonglong(cast_float_to_ulonglong(18446743523953737728.0f), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF + todo_gcc ok_eq_ulonglong(cast_float_to_ulonglong(20000000000000000000.0f), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF + + // float to unsigned long long cast (negative values) + ok_eq_ulonglong(cast_float_to_ulonglong(-0.0f), 0ull); + ok_eq_ulonglong(cast_float_to_ulonglong(-0.5f), 0ull); + ok_eq_ulonglong(cast_float_to_ulonglong(-1.0f), 18446744073709551615ull); +#ifdef OLD_BEHAVIOR + ok_eq_ulonglong(cast_float_to_ulonglong(-10.0f), ULLONG_MAX); + ok_eq_ulonglong(cast_float_to_ulonglong(-1147483648.0f), ULLONG_MAX); + ok_eq_ulonglong(cast_float_to_ulonglong(-2147483648.0f), ULLONG_MAX); + ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868863.9f), ULLONG_MAX); + ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868864.0f), ULLONG_MAX); + ok_eq_ulonglong(cast_float_to_ulonglong(-9223372036854775808.0f), ULLONG_MAX); +#else + ok_eq_ulonglong(cast_float_to_ulonglong(-10.0f), (unsigned long long)-10); + ok_eq_ulonglong(cast_float_to_ulonglong(-1147483648.0f), (unsigned long long)-1147483648ll); + ok_eq_ulonglong(cast_float_to_ulonglong(-2147483648.0f), (unsigned long long)-2147483648ll); + ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868863.9f), (unsigned long long)-9223371487098961920); + ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868864.0f), (unsigned long long)(-9223372036854775807ll - 1)); // 0x8000000000000000 / ULONGLONG_OVERFLOW + ok_eq_ulonglong(cast_float_to_ulonglong(-9223372036854775808.0f), (unsigned long long)(-9223372036854775807ll - 1)); // 0x8000000000000000 / ULONGLONG_OVERFLOW +#endif + ok_eq_ulonglong(cast_float_to_ulonglong(-100000000000000000000.0f), ULONGLONG_OVERFLOW); +} + +void Test_double(void) +{ + // double to long cast + ok_eq_long(cast_double_to_long(0.0), 0l); + ok_eq_long(cast_double_to_long(1.0), 1l); + ok_eq_long(cast_double_to_long(-1.0), -1l); + ok_eq_long(cast_double_to_long(0.5), 0l); + ok_eq_long(cast_double_to_long(-0.5), 0l); + ok_eq_long(cast_double_to_long(0.999999999), 0l); + ok_eq_long(cast_double_to_long(-0.999999999), 0l); + ok_eq_long(cast_double_to_long(2147483647.99999), 2147483647l); + ok_eq_long(cast_double_to_long(-2147483647.99999), -2147483647l); + ok_eq_long(cast_double_to_long(2147483648.0), LONG_MIN); // -2147483648 + ok_eq_long(cast_double_to_long(-2147483648.0), LONG_MIN); // -2147483648 + ok_eq_long(cast_double_to_long(10000000000.0), LONG_MIN); + ok_eq_long(cast_double_to_long(-10000000000.0), LONG_MIN); + + // double to unsigned long cast (positive values) + ok_eq_ulong(cast_double_to_ulong(0.0), 0ul); + ok_eq_ulong(cast_double_to_ulong(1.0), 1ul); + ok_eq_ulong(cast_double_to_ulong(0.5), 0ul); + ok_eq_ulong(cast_double_to_ulong(0.999999999), 0ul); + ok_eq_ulong(cast_double_to_ulong(2147483648.0), 2147483648ul); // 0x80000000 + ok_eq_ulong(cast_double_to_ulong(4294967295.0), 4294967295ul); // 0xFFFFFFFF + ok_eq_ulong(cast_double_to_ulong(4294967296.0), ULONG_OVERFLOW); + + // double to unsigned long cast (negative values) + ok_eq_ulong(cast_double_to_ulong(-0.0), 0ul); + ok_eq_ulong(cast_double_to_ulong(-0.5), 0ul); + ok_eq_ulong(cast_double_to_ulong(-1.0), ULONG_MAX); +#ifdef OLD_BEHAVIOR + ok_eq_ulong(cast_double_to_ulong(-10.0), ULONG_MAX); + ok_eq_ulong(cast_double_to_ulong(-1147483648.0), ULONG_MAX); + ok_eq_ulong(cast_double_to_ulong(-2147483648.0), ULONG_MAX); +#else + ok_eq_ulong(cast_double_to_ulong(-10.0), (unsigned long)-10); + ok_eq_ulong(cast_double_to_ulong(-1147483648.0), (unsigned long)-1147483648ll); + ok_eq_ulong(cast_double_to_ulong(-2147483648.0), (unsigned long)-2147483648ll); +#endif + + // double to long long cast + ok_eq_longlong(cast_double_to_longlong(0.0), 0ll); + ok_eq_longlong(cast_double_to_longlong(1.0), 1ll); + ok_eq_longlong(cast_double_to_longlong(-1.0), -1ll); + ok_eq_longlong(cast_double_to_longlong(0.5), 0ll); + ok_eq_longlong(cast_double_to_longlong(-0.5), 0ll); + ok_eq_longlong(cast_double_to_longlong(0.999999), 0ll); + ok_eq_longlong(cast_double_to_longlong(-0.999999), 0ll); + ok_eq_longlong(cast_double_to_longlong(9223372036854775295.9), 9223372036854774784ll); + ok_eq_longlong(cast_double_to_longlong(9223372036854775296.0), LLONG_MIN); + ok_eq_longlong(cast_double_to_longlong(-9223372036854775295.9), -9223372036854774784ll); + ok_eq_longlong(cast_double_to_longlong(-9223372036854775296.0), LLONG_MIN); + ok_eq_longlong(cast_double_to_longlong(100000000000000000000.0), LLONG_MIN); + ok_eq_longlong(cast_double_to_longlong(-100000000000000000000.0), LLONG_MIN); + + // double to unsigned long long cast (positive values) + ok_eq_ulonglong(cast_double_to_ulonglong(0.0), 0ull); + ok_eq_ulonglong(cast_double_to_ulonglong(1.0), 1ull); + ok_eq_ulonglong(cast_double_to_ulonglong(0.5), 0ull); + ok_eq_ulonglong(cast_double_to_ulonglong(0.999999), 0ull); + ok_eq_ulonglong(cast_double_to_ulonglong(9223372036854774784.0), 9223372036854774784ull); // 0x7FFFFFFFFFFFFC00 + ok_eq_ulonglong(cast_double_to_ulonglong(9223372036854775808.0), 9223372036854775808ull); // 0x8000000000000000 + ok_eq_ulonglong(cast_double_to_ulonglong(18446744073709550591.9), 18446744073709549568ull); // 0xFFFFFFFFFFFFF800 + todo_gcc ok_eq_ulonglong(cast_double_to_ulonglong(18446744073709550592.0), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF + todo_gcc ok_eq_ulonglong(cast_double_to_ulonglong(18446744073709551616.0), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF + todo_gcc ok_eq_ulonglong(cast_double_to_ulonglong(20000000000000000000.0), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF + + // float to unsigned long long cast (negative values) + ok_eq_ulonglong(cast_double_to_ulonglong(-0.0), 0ull); + ok_eq_ulonglong(cast_double_to_ulonglong(-0.5), 0ull); + ok_eq_ulonglong(cast_double_to_ulonglong(-1.0), 18446744073709551615ull); +#ifdef OLD_BEHAVIOR + ok_eq_ulonglong(cast_double_to_ulonglong(-10.0), ULLONG_MAX); + ok_eq_ulonglong(cast_double_to_ulonglong(-1147483648.0), ULLONG_MAX); + ok_eq_ulonglong(cast_double_to_ulonglong(-2147483648.0), ULLONG_MAX); + ok_eq_ulonglong(cast_double_to_ulonglong(-9223371761976868863.9), ULLONG_MAX); + ok_eq_ulonglong(cast_double_to_ulonglong(-9223371761976868864.0), ULLONG_MAX); + ok_eq_ulonglong(cast_double_to_ulonglong(-9223372036854775808.0), ULLONG_MAX); +#else + ok_eq_ulonglong(cast_double_to_ulonglong(-10.0), (unsigned long long)-10); + ok_eq_ulonglong(cast_double_to_ulonglong(-1147483648.0), (unsigned long long)-1147483648ll); + ok_eq_ulonglong(cast_double_to_ulonglong(-2147483648.0), (unsigned long long)-2147483648ll); + ok_eq_ulonglong(cast_double_to_ulonglong(-9223372036854775000.0), (unsigned long long)-9223372036854774784ll); + ok_eq_ulonglong(cast_double_to_ulonglong(-9223372036854775808.0), (unsigned long long)(-9223372036854775807ll - 1)); +#endif + ok_eq_ulonglong(cast_double_to_ulonglong(-100000000000000000000.0), ULONGLONG_OVERFLOW); +} + +START_TEST(floatconv) +{ + Test_float(); + Test_double(); +} diff --git a/modules/rostests/apitests/compiler/testlist.c b/modules/rostests/apitests/compiler/testlist.c index d73f7fd70bb..fe4b55adc21 100644 --- a/modules/rostests/apitests/compiler/testlist.c +++ b/modules/rostests/apitests/compiler/testlist.c @@ -1,16 +1,20 @@ #define STANDALONE #include +extern void func_floatconv(void); extern void func_ms_seh(void); extern void func_pseh(void); extern void func_pseh_cpp(void); const struct test winetest_testlist[] = { + { "floatconv", func_floatconv }, +#ifndef __VS_PROJECT__ #if !(defined(__GNUC__) && defined(_M_AMD64)) { "ms-seh", func_ms_seh }, #endif { "pseh", func_pseh }, { "pseh_cpp", func_pseh_cpp }, +#endif /* __VS_PROJECT__ */ { 0, 0 } };