From 0a00a1f5b03b23e2e63482d7acbaac4e574ff764 Mon Sep 17 00:00:00 2001 From: Marcin Hajder Date: Tue, 27 Aug 2024 17:41:05 +0200 Subject: [PATCH] Added printf test for double type cases (#2022) according to work plan for issue https://github.com/KhronosGroup/OpenCL-CTS/issues/1058 --- test_common/harness/kernelHelpers.cpp | 29 ++- test_common/harness/kernelHelpers.h | 4 +- test_conformance/printf/test_printf.cpp | 52 ++++- test_conformance/printf/test_printf.h | 3 + test_conformance/printf/util_printf.cpp | 279 +++++++++++++++++++++--- 5 files changed, 309 insertions(+), 58 deletions(-) diff --git a/test_common/harness/kernelHelpers.cpp b/test_common/harness/kernelHelpers.cpp index 633b05e5..c307fca5 100644 --- a/test_common/harness/kernelHelpers.cpp +++ b/test_common/harness/kernelHelpers.cpp @@ -1511,30 +1511,27 @@ size_t get_min_alignment(cl_context context) return align_size; } -cl_device_fp_config get_default_rounding_mode(cl_device_id device, - const cl_uint ¶m) +cl_device_fp_config get_default_rounding_mode(const cl_device_id device, + const cl_uint param) { - if (param == CL_DEVICE_DOUBLE_FP_CONFIG) - test_error_ret( - -1, - "FAILURE: CL_DEVICE_DOUBLE_FP_CONFIG not supported by this routine", - 0); - char profileStr[128] = ""; - cl_device_fp_config single = 0; - int error = clGetDeviceInfo(device, param, sizeof(single), &single, NULL); + cl_device_fp_config config = 0; + int error = clGetDeviceInfo(device, param, sizeof(config), &config, NULL); if (error) { - std::string message = std::string("Unable to get device ") - + std::string(param == CL_DEVICE_HALF_FP_CONFIG - ? "CL_DEVICE_HALF_FP_CONFIG" - : "CL_DEVICE_SINGLE_FP_CONFIG"); + std::string config_name = "CL_DEVICE_SINGLE_FP_CONFIG"; + if (param == CL_DEVICE_HALF_FP_CONFIG) + config_name = "CL_DEVICE_HALF_FP_CONFIG"; + else if (param == CL_DEVICE_DOUBLE_FP_CONFIG) + config_name = "CL_DEVICE_DOUBLE_FP_CONFIG"; + std::string message = + std::string("Unable to get device ") + config_name; test_error_ret(error, message.c_str(), 0); } - if (single & CL_FP_ROUND_TO_NEAREST) return CL_FP_ROUND_TO_NEAREST; + if (config & CL_FP_ROUND_TO_NEAREST) return CL_FP_ROUND_TO_NEAREST; - if (0 == (single & CL_FP_ROUND_TO_ZERO)) + if (0 == (config & CL_FP_ROUND_TO_ZERO)) test_error_ret(-1, "FAILURE: device must support either " "CL_FP_ROUND_TO_ZERO or CL_FP_ROUND_TO_NEAREST", diff --git a/test_common/harness/kernelHelpers.h b/test_common/harness/kernelHelpers.h index 86a69192..518b2749 100644 --- a/test_common/harness/kernelHelpers.h +++ b/test_common/harness/kernelHelpers.h @@ -157,8 +157,8 @@ size_t get_min_alignment(cl_context context); /* Helper to obtain the default rounding mode for single precision computation. * (Double is always CL_FP_ROUND_TO_NEAREST.) Returns 0 on error. */ cl_device_fp_config -get_default_rounding_mode(cl_device_id device, - const cl_uint ¶m = CL_DEVICE_SINGLE_FP_CONFIG); +get_default_rounding_mode(const cl_device_id device, + const cl_uint param = CL_DEVICE_SINGLE_FP_CONFIG); #define PASSIVE_REQUIRE_IMAGE_SUPPORT(device) \ if (checkForImageSupport(device)) \ diff --git a/test_conformance/printf/test_printf.cpp b/test_conformance/printf/test_printf.cpp index 3d539ed5..d59e0682 100644 --- a/test_conformance/printf/test_printf.cpp +++ b/test_conformance/printf/test_printf.cpp @@ -698,6 +698,15 @@ int doTest(cl_command_queue queue, cl_context context, return TEST_SKIPPED_ITSELF; } + if ((allTestCase[testId]->_type == TYPE_DOUBLE + || allTestCase[testId]->_type == TYPE_DOUBLE_LIMITS) + && !is_extension_available(device, "cl_khr_fp64")) + { + log_info("Skipping double because cl_khr_fp64 extension is not " + "supported.\n"); + return TEST_SKIPPED_ITSELF; + } + auto& genParams = allTestCase[testId]->_genParameters; auto fail_count = s_test_fail; @@ -708,18 +717,25 @@ int doTest(cl_command_queue queue, cl_context context, { if (allTestCase[testId]->_type == TYPE_VECTOR) { - if ((strcmp(allTestCase[testId]->_genParameters[testNum].dataType, - "half") - == 0) - && !is_extension_available(device, "cl_khr_fp16")) - { - log_info("Skipping half because cl_khr_fp16 extension is not " - "supported.\n"); + auto is_vector_type_supported = [&](const char* type_name, + const char* ext_name) { + if ((strcmp(genParams[testNum].dataType, type_name) == 0) + && !is_extension_available(device, ext_name)) + { + log_info("Skipping %s because %s extension " + "is not supported.\n", + type_name, ext_name); - s_test_skip++; - s_test_cnt++; - continue; - } + s_test_skip++; + s_test_cnt++; + return false; + } + return true; + }; + + if (!is_vector_type_supported("half", "cl_khr_fp16")) continue; + + if (!is_vector_type_supported("double", "cl_khr_fp64")) continue; // Long support for varible type if (!strcmp(allTestCase[testId]->_genParameters[testNum].dataType, @@ -935,6 +951,18 @@ int test_float_limits(cl_device_id deviceID, cl_context context, return doTest(gQueue, gContext, TYPE_FLOAT_LIMITS, deviceID); } +int test_double(cl_device_id deviceID, cl_context context, + cl_command_queue queue, int num_elements) +{ + return doTest(gQueue, gContext, TYPE_DOUBLE, deviceID); +} + +int test_double_limits(cl_device_id deviceID, cl_context context, + cl_command_queue queue, int num_elements) +{ + return doTest(gQueue, gContext, TYPE_DOUBLE_LIMITS, deviceID); +} + int test_octal(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) { @@ -1020,6 +1048,8 @@ test_definition test_list[] = { ADD_TEST(half_limits), ADD_TEST(float), ADD_TEST(float_limits), + ADD_TEST(double), + ADD_TEST(double_limits), ADD_TEST(octal), ADD_TEST(unsigned), ADD_TEST(hexadecimal), diff --git a/test_conformance/printf/test_printf.h b/test_conformance/printf/test_printf.h index a2cd9ed2..51f35117 100644 --- a/test_conformance/printf/test_printf.h +++ b/test_conformance/printf/test_printf.h @@ -50,6 +50,8 @@ enum PrintfTestType TYPE_HALF_LIMITS, TYPE_FLOAT, TYPE_FLOAT_LIMITS, + TYPE_DOUBLE, + TYPE_DOUBLE_LIMITS, TYPE_OCTAL, TYPE_UNSIGNED, TYPE_HEXADEC, @@ -80,6 +82,7 @@ struct printDataGenParameters static std::vector correctBufferInt; static std::vector correctBufferHalf; static std::vector correctBufferFloat; +static std::vector correctBufferDouble; static std::vector correctBufferOctal; static std::vector correctBufferUnsigned; static std::vector correctBufferHexadecimal; diff --git a/test_conformance/printf/util_printf.cpp b/test_conformance/printf/util_printf.cpp index 03d5eb17..759a8dea 100644 --- a/test_conformance/printf/util_printf.cpp +++ b/test_conformance/printf/util_printf.cpp @@ -26,6 +26,8 @@ static void intRefBuilder(printDataGenParameters&, char*, const size_t); static void halfRefBuilder(printDataGenParameters&, char* rResult, const size_t); static void floatRefBuilder(printDataGenParameters&, char* rResult, const size_t); +static void doubleRefBuilder(printDataGenParameters&, char* rResult, + const size_t); static void octalRefBuilder(printDataGenParameters&, char*, const size_t); static void unsignedRefBuilder(printDataGenParameters&, char*, const size_t); static void hexRefBuilder(printDataGenParameters&, char*, const size_t); @@ -295,99 +297,99 @@ std::vector printFloatGenParameters = { // Default(right)-justified - { { "%f" }, "10.3456" }, + { { "%f" }, "10.3456f" }, // One position after the decimal,default(right)-justified - { { "%.1f" }, "10.3456" }, + { { "%.1f" }, "10.3456f" }, // Two positions after the decimal,default(right)-justified - { { "%.2f" }, "10.3456" }, + { { "%.2f" }, "10.3456f" }, //(Minimum)Eight-wide,three positions after the // decimal,default(right)-justified - { { "%8.3f" }, "10.3456" }, + { { "%8.3f" }, "10.3456f" }, //(Minimum)Eight-wide,two positions after the // decimal,zero-filled,default(right)-justified - { { "%08.2f" }, "10.3456" }, + { { "%08.2f" }, "10.3456f" }, //(Minimum)Eight-wide,two positions after the decimal,left-justified - { { "%-8.2f" }, "10.3456" }, + { { "%-8.2f" }, "10.3456f" }, //(Minimum)Eight-wide,two positions after the decimal,with // sign,default(right)-justified - { { "%+8.2f" }, "-10.3456" }, + { { "%+8.2f" }, "-10.3456f" }, // Zero positions after the // decimal([floor]rounding),default(right)-justified - { { "%.0f" }, "0.1" }, + { { "%.0f" }, "0.1f" }, // Zero positions after the decimal([ceil]rounding),default(right)-justified - { { "%.0f" }, "0.6" }, + { { "%.0f" }, "0.6f" }, // Zero-filled,default positions number after the // decimal,default(right)-justified - { { "%0f" }, "0.6" }, + { { "%0f" }, "0.6f" }, // Double argument representing floating-point,used by f // style,default(right)-justified - { { "%4g" }, "12345.6789" }, + { { "%4g" }, "12345.6789f" }, // Double argument representing floating-point,used by e // style,default(right)-justified - { { "%4.2g" }, "12345.6789" }, + { { "%4.2g" }, "12345.6789f" }, // Double argument representing floating-point,used by f // style,default(right)-justified - { { "%4G" }, "0.0000023" }, + { { "%4G" }, "0.0000023f" }, // Double argument representing floating-point,used by e // style,default(right)-justified - { { "%4G" }, "0.023" }, + { { "%4G" }, "0.023f" }, // Double argument representing floating-point,with // exponent,left-justified,default(right)-justified // Use a value that is exactly representable as 32-bit float. - { { "%-#20.15e" }, "789456128.0" }, + { { "%-#20.15e" }, "789456128.f" }, // Double argument representing floating-point,with // exponent,left-justified,with sign,capital E,default(right)-justified // Use a value that is exactly representable as 32-bit float. - { { "%+#21.15E" }, "789456128.0" }, + { { "%+#21.15E" }, "789456128.f" }, // Double argument representing floating-point,in [-]xh.hhhhpAd style - { { "%.6a" }, "0.1" }, + { { "%.6a" }, "0.1f" }, //(Minimum)Ten-wide,Double argument representing floating-point,in // xh.hhhhpAd style,default(right)-justified - { { "%10.2a" }, "9990.235" }, + { { "%10.2a" }, "9990.235f" }, //(Minimum)Ten-wide,two positions after the decimal,with // a blank space inserted before the value, default(right)-justified - { { "% 10.2f" }, "1.25" }, + { { "% 10.2f" }, "1.25f" }, //(Minimum)Eight-wide,two positions after the decimal,with // zeros inserted before the value, default(right)-justified - { { "%08.2f" }, "3.14" }, + { { "%08.2f" }, "3.14f" }, }; //--------------------------------------------------------- @@ -485,6 +487,200 @@ testCase testCaseFloatLimits = { }; +//============================================== + +// double + +//============================================== + + +//-------------------------------------------------------- + +// [string] format | [string] double-data representation | + +//-------------------------------------------------------- + +std::vector printDoubleGenParameters = { + + // Default(right)-justified + + { { "%f" }, "10.3456" }, + + // One position after the decimal,default(right)-justified + + { { "%.1f" }, "10.3456" }, + + // Two positions after the decimal,default(right)-justified + + { { "%.2f" }, "10.3456" }, + + //(Minimum)Eight-wide,three positions after the + // decimal,default(right)-justified + + { { "%8.3f" }, "10.3456" }, + + //(Minimum)Eight-wide,two positions after the + // decimal,zero-filled,default(right)-justified + + { { "%08.2f" }, "10.3456" }, + + //(Minimum)Eight-wide,two positions after the decimal,left-justified + + { { "%-8.2f" }, "10.3456" }, + + //(Minimum)Eight-wide,two positions after the decimal,with + // sign,default(right)-justified + + { { "%+8.2f" }, "-10.3456" }, + + // Zero positions after the + // decimal([floor]rounding),default(right)-justified + + { { "%.0f" }, "0.1" }, + + // Zero positions after the decimal([ceil]rounding),default(right)-justified + + { { "%.0f" }, "0.6" }, + + // Zero-filled,default positions number after the + // decimal,default(right)-justified + + { { "%0f" }, "0.6" }, + + // Double argument representing floating-point,used by f + // style,default(right)-justified + + { { "%4g" }, "12345.6789" }, + + // Double argument representing floating-point,used by e + // style,default(right)-justified + + { { "%4.2g" }, "12345.6789" }, + + // Double argument representing floating-point,used by f + // style,default(right)-justified + + { { "%4G" }, "0.0000023" }, + + // Double argument representing floating-point,used by e + // style,default(right)-justified + + { { "%4G" }, "0.023" }, + + // Double argument representing floating-point,with + // exponent,left-justified,default(right)-justified + + { { "%-#20.15e" }, "789456123.0" }, + + // Double argument representing floating-point,with + // exponent,left-justified,with sign,capital E,default(right)-justified + + { { "%+#21.15E" }, "789456123.0" }, + + // Double argument representing floating-point,in [-]xh.hhhhpAd style + + { { "%.6a" }, "0.1" }, + + //(Minimum)Ten-wide,Double argument representing floating-point,in + // xh.hhhhpAd style,default(right)-justified + + { { "%10.2a" }, "9990.235" }, +}; + +//--------------------------------------------------------- + +// Test case for double | + +//--------------------------------------------------------- + +testCase testCaseDouble = { + + TYPE_DOUBLE, + + correctBufferDouble, + + printDoubleGenParameters, + + doubleRefBuilder, + + kdouble + +}; + +//============================================== + +// double limits + +//============================================== + + +//-------------------------------------------------------- + +// [string] double | [string] double-data representation | + +//-------------------------------------------------------- + + +std::vector printDoubleLimitsGenParameters = { + + // Infinity (1.0/0.0) + { { "%f", "%e", "%g", "%a" }, "1.0/0.0" }, + + // NaN + { { "%f", "%e", "%g", "%a" }, "nan(0UL)" }, + + // NaN + { { "%f", "%e", "%g", "%a" }, "acospi(2.0)" }, + + // Infinity (1.0/0.0) + { { "%F", "%E", "%G", "%A" }, "1.0/0.0" }, + + // NaN + { { "%F", "%E", "%G", "%A" }, "nan(0UL)" }, + + // NaN + { { "%F", "%E", "%G", "%A" }, "acospi(2.0)" } +}; +//-------------------------------------------------------- + +// Lookup table - [string]double-correct buffer | + +//-------------------------------------------------------- + +std::vector correctBufferDoubleLimits = { + + "inf", + + "nan", + + "nan", + + "INF", + + "NAN", + + "NAN" + +}; + +//--------------------------------------------------------- + +// Test case for float | + +//--------------------------------------------------------- + +testCase testCaseDoubleLimits = { + + TYPE_DOUBLE_LIMITS, + + correctBufferDoubleLimits, + + printDoubleLimitsGenParameters, + + NULL + +}; + //========================================================= // octal @@ -1208,11 +1404,12 @@ testCase testCaseMixedFormat = { TYPE_MIXED_FORMAT_RANDOM, //------------------------------------------------------------------------------- std::vector allTestCase = { - &testCaseInt, &testCaseHalf, &testCaseHalfLimits, - &testCaseFloat, &testCaseFloatLimits, &testCaseOctal, - &testCaseUnsigned, &testCaseHexadecimal, &testCaseChar, - &testCaseString, &testCaseFormatString, &testCaseVector, - &testCaseAddrSpace, &testCaseMixedFormat + &testCaseInt, &testCaseHalf, &testCaseHalfLimits, + &testCaseFloat, &testCaseFloatLimits, &testCaseDouble, + &testCaseDoubleLimits, &testCaseOctal, &testCaseUnsigned, + &testCaseHexadecimal, &testCaseChar, &testCaseString, + &testCaseFormatString, &testCaseVector, &testCaseAddrSpace, + &testCaseMixedFormat }; //----------------------------------------- @@ -1344,6 +1541,13 @@ static void floatRefBuilder(printDataGenParameters& params, char* refResult, con strtof(params.dataRepresentation, NULL)); } +static void doubleRefBuilder(printDataGenParameters& params, char* refResult, + const size_t refSize) +{ + snprintf(refResult, refSize, params.genericFormats.front().c_str(), + strtod(params.dataRepresentation, NULL)); +} + static void octalRefBuilder(printDataGenParameters& params, char* refResult, const size_t refSize) { const unsigned long int data = strtoul(params.dataRepresentation, NULL, 10); @@ -1374,11 +1578,17 @@ static void hexRefBuilder(printDataGenParameters& params, char* refResult, const */ void generateRef(const cl_device_id device) { + bool fp16_supported = is_extension_available(device, "cl_khr_fp16"); + bool fp64_supported = is_extension_available(device, "cl_khr_fp64"); + const cl_device_fp_config fpConfigSingle = get_default_rounding_mode(device); const cl_device_fp_config fpConfigHalf = (half_rounding_mode == CL_HALF_RTE) ? CL_FP_ROUND_TO_NEAREST : CL_FP_ROUND_TO_ZERO; + const cl_device_fp_config fpConfigDouble = fp64_supported + ? get_default_rounding_mode(device, CL_DEVICE_DOUBLE_FP_CONFIG) + : 0; const RoundingMode hostRound = get_round(); // Map device rounding to CTS rounding type @@ -1413,10 +1623,21 @@ void generateRef(const cl_device_id device) // Make sure the reference result is empty assert(caseToTest->_correctBuffer.size() == 0); - const cl_device_fp_config* fpConfig = &fpConfigSingle; - if (caseToTest->_type == TYPE_HALF - || caseToTest->_type == TYPE_HALF_LIMITS) - fpConfig = &fpConfigHalf; + const cl_device_fp_config* fpConfig = nullptr; + switch (caseToTest->_type) + { + case TYPE_HALF: + case TYPE_HALF_LIMITS: + if (!fp16_supported) continue; + fpConfig = &fpConfigHalf; + break; + case TYPE_DOUBLE: + case TYPE_DOUBLE_LIMITS: + if (!fp64_supported) continue; + fpConfig = &fpConfigDouble; + break; + default: fpConfig = &fpConfigSingle; break; + } RoundingMode deviceRound = get_rounding(*fpConfig); // Loop through each input