diff --git a/External/HIP/CMakeLists.txt b/External/HIP/CMakeLists.txt index dda0ad4f8d..dc2f3e1b80 100644 --- a/External/HIP/CMakeLists.txt +++ b/External/HIP/CMakeLists.txt @@ -8,10 +8,13 @@ macro(create_local_hip_tests VariantSuffix) # Set per-source compilation/link options set_source_files_properties(with-fopenmp.hip PROPERTIES COMPILE_FLAGS -fopenmp) + set_source_files_properties(host-min-max.hip PROPERTIES + COMPILE_FLAGS -D__HIP_DEFINE_MIXED_HOST_MIN_MAX__) # Add HIP tests to be added to hip-tests-simple list(APPEND HIP_LOCAL_TESTS empty) list(APPEND HIP_LOCAL_TESTS with-fopenmp) list(APPEND HIP_LOCAL_TESTS saxpy) + list(APPEND HIP_LOCAL_TESTS host-min-max) list(APPEND HIP_LOCAL_TESTS InOneWeekend) list(APPEND HIP_LOCAL_TESTS TheNextWeek) diff --git a/External/HIP/host-min-max.hip b/External/HIP/host-min-max.hip new file mode 100644 index 0000000000..0dcf47befd --- /dev/null +++ b/External/HIP/host-min-max.hip @@ -0,0 +1,96 @@ +#include +#include t +#include +#include +#include +#include +#include +#include + +// Convert typeid name to C++ type name +std::string demangle(const char *name) { + static const std::map demangleMap = { + {'i', "int"}, {'f', "float"}, + {'d', "double"}, {'j', "unsigned int"}, + {'l', "long"}, {'m', "unsigned long"}, + {'x', "long long"}, {'y', "unsigned long long"}}; + + auto it = demangleMap.find(name[0]); + if (it != demangleMap.end()) { + return it->second; + } else { + return std::string(name); + } +} + +void checkHipCall(hipError_t status, const char *msg) { + if (status != hipSuccess) { + std::cerr << "HIP Error: " << msg << " - " << hipGetErrorString(status) + << std::endl; + std::abort(); + } +} + +template +void compareResults(T1 hipResult, T2 stdResult, const std::string &testName) { + using CommonType = typename std::common_type::type; + if (static_cast(hipResult) != + static_cast(stdResult)) { + std::cerr << testName << " mismatch: HIP result " << hipResult << " (" + << demangle(typeid(hipResult).name()) << "), std result " + << stdResult << " (" << demangle(typeid(stdResult).name()) << ")" + << std::endl; + std::abort(); + } +} + +template void runTest(T1 a, T2 b) { + std::cout << "\nTesting with values: " << a << " (" + << demangle(typeid(a).name()) << ") and " << b << " (" + << demangle(typeid(b).name()) << ")" << std::endl; + + // Using std::min and std::max as reference + // The two arguments are converted to std::common_type first then passed + // to std::min/max. This assumes compatiblity with CUDA. + using CommonType = typename std::common_type::type; + CommonType stdMinResult = std::min(a, b); + CommonType stdMaxResult = std::max(a, b); + std::cout << "Host std::min result: " << stdMinResult + << " (Type: " << demangle(typeid(stdMinResult).name()) << ")" + << std::endl; + std::cout << "Host std::max result: " << stdMaxResult + << " (Type: " << demangle(typeid(stdMaxResult).name()) << ")" + << std::endl; + + // Using HIP's global min/max functions + CommonType hipMinResult = min(a, b); + CommonType hipMaxResult = max(a, b); + std::cout << "Host HIP min result: " << hipMinResult + << " (Type: " << demangle(typeid(hipMinResult).name()) << ")" + << std::endl; + std::cout << "Host HIP max result: " << hipMaxResult + << " (Type: " << demangle(typeid(hipMaxResult).name()) << ")" + << std::endl; + + // Ensure the host HIP and std results match + compareResults(hipMinResult, stdMinResult, "HIP vs std min"); + compareResults(hipMaxResult, stdMaxResult, "HIP vs std max"); +} + +int main() { + checkHipCall(hipSetDevice(0), "hipSetDevice failed"); + + // For mixed signed/unsigned integer arguments, assuming CUDA compatibility, + // i.e. the signed integer is implicitly converted to unsigned type and then + // compared. + runTest(10uLL, -5LL); // Testing with unsigned int and long long + runTest(-15, 20u); // Testing with int and unsigned int + runTest(2147483647, 2147483648u); // Testing with int and unsigned int + runTest( + -922337203685477580LL, + 922337203685477580uLL); // Testing with long long and unsigned long long + runTest(2.5f, 3.14159); // Testing with float and double + + std::cout << "\nPass\n"; + return 0; +} diff --git a/External/HIP/host-min-max.reference_output b/External/HIP/host-min-max.reference_output new file mode 100644 index 0000000000..da45ec407d --- /dev/null +++ b/External/HIP/host-min-max.reference_output @@ -0,0 +1,32 @@ + +Testing with values: 10 (unsigned long long) and -5 (long long) +Host std::min result: 10 (Type: unsigned long long) +Host std::max result: 18446744073709551611 (Type: unsigned long long) +Host HIP min result: 10 (Type: unsigned long long) +Host HIP max result: 18446744073709551611 (Type: unsigned long long) + +Testing with values: -15 (int) and 20 (unsigned int) +Host std::min result: 20 (Type: unsigned int) +Host std::max result: 4294967281 (Type: unsigned int) +Host HIP min result: 20 (Type: unsigned int) +Host HIP max result: 4294967281 (Type: unsigned int) + +Testing with values: 2147483647 (int) and 2147483648 (unsigned int) +Host std::min result: 2147483647 (Type: unsigned int) +Host std::max result: 2147483648 (Type: unsigned int) +Host HIP min result: 2147483647 (Type: unsigned int) +Host HIP max result: 2147483648 (Type: unsigned int) + +Testing with values: -922337203685477580 (long long) and 922337203685477580 (unsigned long long) +Host std::min result: 922337203685477580 (Type: unsigned long long) +Host std::max result: 17524406870024074036 (Type: unsigned long long) +Host HIP min result: 922337203685477580 (Type: unsigned long long) +Host HIP max result: 17524406870024074036 (Type: unsigned long long) + +Testing with values: 2.5 (float) and 3.14159 (double) +Host std::min result: 2.5 (Type: double) +Host std::max result: 3.14159 (Type: double) +Host HIP min result: 2.5 (Type: double) +Host HIP max result: 3.14159 (Type: double) + +Pass