diff --git a/test_common/harness/kernelHelpers.cpp b/test_common/harness/kernelHelpers.cpp index 194de05c..566700eb 100644 --- a/test_common/harness/kernelHelpers.cpp +++ b/test_common/harness/kernelHelpers.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #if defined(_WIN32) std::string slash = "\\"; @@ -809,6 +810,43 @@ int create_single_kernel_helper(cl_context context, const char *buildOptions, const bool openclCXX) { + // For the logic that automatically adds -cl-std it is much cleaner if the + // build options have RAII. This buffer will store the potentially updated + // build options, in which case buildOptions will point at the string owned + // by this buffer. + std::string build_options_internal{ buildOptions ? buildOptions : "" }; + + // Check the build options for the -cl-std option. + if (!buildOptions || !strstr(buildOptions, "-cl-std")) + { + // If the build option isn't present add it using the latest OpenCL-C + // version supported by the device. This allows calling code to force a + // particular CL C version if it is required, but also means that + // callers need not specify a version if they want to assume the most + // recent CL C. + + auto version = get_max_OpenCL_C_for_context(context); + + std::string cl_std{}; + if (version >= Version(3, 0)) + { + cl_std = "-cl-std=CL3.0"; + } + else if (version >= Version(2, 0) && version < Version(3, 0)) + { + cl_std = "-cl-std=CL2.0"; + } + else + { + // If the -cl-std build option is not specified, the highest OpenCL + // C 1.x language version supported by each device is used when + // compiling the program for each device. + cl_std = ""; + } + build_options_internal += ' '; + build_options_internal += cl_std; + buildOptions = build_options_internal.c_str(); + } int error; // Create OpenCL C++ program if(openclCXX) @@ -1543,3 +1581,115 @@ int printDeviceHeader( cl_device_id device ) return CL_SUCCESS; } + +Version get_device_cl_c_version(cl_device_id device) +{ + // Get the device OpenCL version. + auto device_cl_version = get_device_cl_version(device); + + // If the device version >= 3.0 it must support the + // CL_DEVICE_OPENCL_C_ALL_VERSIONS query from which we can extract the most + // recent CL C version supported by the device. + if (device_cl_version >= Version{ 3, 0 }) + { + size_t opencl_c_all_versions_size_in_bytes{}; + auto error = + clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, 0, nullptr, + &opencl_c_all_versions_size_in_bytes); + test_error_ret( + error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", + (Version{ -1, 0 })); + std::vector name_versions( + opencl_c_all_versions_size_in_bytes / sizeof(cl_name_version)); + error = clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_ALL_VERSIONS, + opencl_c_all_versions_size_in_bytes, + name_versions.data(), nullptr); + test_error_ret( + error, "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_ALL_VERSIONS", + (Version{ -1, 0 })); + + Version max_supported_cl_c_version{}; + for (const auto &name_version : name_versions) + { + Version current_version{ CL_VERSION_MAJOR(name_version.version), + CL_VERSION_MINOR(name_version.version) }; + max_supported_cl_c_version = + (current_version > max_supported_cl_c_version) + ? current_version + : max_supported_cl_c_version; + } + return max_supported_cl_c_version; + } + + // The second special case is OpenCL-1.0 where CL_DEVICE_OPENCL_C_VERSION + // did not exist, but since this is just the first version we can + // return 1.0. + if (device_cl_version == Version{ 1, 0 }) + { + return Version{ 1, 0 }; + } + + // Otherwise we know we have a 1.1 <= device_version <= 2.0 where all CL C + // versions are backwards compatible, hence querying with the + // CL_DEVICE_OPENCL_C_VERSION query must return the most recent supported + // OpenCL C version. + size_t opencl_c_version_size_in_bytes{}; + auto error = clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_VERSION, 0, nullptr, + &opencl_c_version_size_in_bytes); + test_error_ret(error, + "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_VERSION\n", + (Version{ -1, 0 })); + + std::string opencl_c_version(opencl_c_version_size_in_bytes, '\0'); + error = + clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_VERSION, + opencl_c_version.size(), &opencl_c_version[0], nullptr); + + test_error_ret(error, + "clGetDeviceInfo failed for CL_DEVICE_OPENCL_C_VERSION\n", + (Version{ -1, 0 })); + + // Scrape out the major, minor pair from the string. + auto major = opencl_c_version[opencl_c_version.find('.') - 1]; + auto minor = opencl_c_version[opencl_c_version.find('.') + 1]; + + return Version{ major - '0', minor - '0' }; +} + +Version get_max_OpenCL_C_for_context(cl_context context) +{ + // Get all the devices in the context and find the maximum + // universally supported OpenCL C version. + size_t devices_size_in_bytes{}; + auto error = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, nullptr, + &devices_size_in_bytes); + test_error_ret(error, "clGetDeviceInfo failed for CL_CONTEXT_DEVICES", + (Version{ -1, 0 })); + std::vector devices(devices_size_in_bytes + / sizeof(cl_device_id)); + error = clGetContextInfo(context, CL_CONTEXT_DEVICES, devices_size_in_bytes, + devices.data(), nullptr); + auto current_version = get_device_cl_c_version(devices[0]); + std::for_each(std::next(devices.begin()), devices.end(), + [¤t_version](cl_device_id device) { + auto device_version = get_device_cl_c_version(device); + // OpenCL 3.0 is not backwards compatible with 2.0. + // If we have 3.0 and 2.0 in the same driver we + // use 1.2. + if (((device_version >= Version(2, 0) + && device_version < Version(3, 0)) + && current_version >= Version(3, 0)) + || (device_version >= Version(3, 0) + && (current_version >= Version(2, 0) + && current_version < Version(3, 0)))) + { + current_version = Version(1, 2); + } + else + { + current_version = + (std::min)(device_version, current_version); + } + }); + return current_version; +} diff --git a/test_common/harness/kernelHelpers.h b/test_common/harness/kernelHelpers.h index e97ec1e0..c4a82431 100644 --- a/test_common/harness/kernelHelpers.h +++ b/test_common/harness/kernelHelpers.h @@ -173,4 +173,12 @@ cl_device_fp_config get_default_rounding_mode( cl_device_id device ); /* Prints out the standard device header for all tests given the device to print for */ extern int printDeviceHeader( cl_device_id device ); +// Gets the latest (potentially non-backward compatible) OpenCL C version +// supported by the device. +Version get_device_cl_c_version(cl_device_id device); + +// Gets the maximum universally supported OpenCL C version in a context, i.e. +// the OpenCL C version supported by all devices in a context. +Version get_max_OpenCL_C_for_context(cl_context context); + #endif // _kernelHelpers_h diff --git a/test_conformance/basic/test_sizeof.cpp b/test_conformance/basic/test_sizeof.cpp index fc3fd0ad..66a6c563 100644 --- a/test_conformance/basic/test_sizeof.cpp +++ b/test_conformance/basic/test_sizeof.cpp @@ -49,13 +49,8 @@ cl_int get_type_size( cl_context context, cl_command_queue queue, const char *ty { sizeof_kernel_code[0] = "#pragma OPENCL EXTENSION cl_khr_fp16 : enable\n"; } - bool deviceLt20 = false; - Version version = get_device_cl_version(device); - if (version < Version(2,0)) { - deviceLt20 = true; - } - - cl_int err = create_single_kernel_helper_with_build_options(context, &p, &k, 4, sizeof_kernel_code, "test_sizeof", deviceLt20 ? "" : "-cl-std=CL2.0"); + cl_int err = create_single_kernel_helper_with_build_options( + context, &p, &k, 4, sizeof_kernel_code, "test_sizeof", nullptr); if( err ) return err; diff --git a/test_conformance/basic/test_wg_barrier.cpp b/test_conformance/basic/test_wg_barrier.cpp index 78675124..e89f4db5 100644 --- a/test_conformance/basic/test_wg_barrier.cpp +++ b/test_conformance/basic/test_wg_barrier.cpp @@ -87,7 +87,9 @@ test_wg_barrier(cl_device_id device, cl_context context, cl_command_queue queue, size_t max_threadgroup_size = 0; MTdata d; - err = create_single_kernel_helper_with_build_options(context, &program, &kernel, 1, &wg_barrier_kernel_code, "compute_sum", "-cl-std=CL2.0" ); + err = create_single_kernel_helper_with_build_options( + context, &program, &kernel, 1, &wg_barrier_kernel_code, "compute_sum", + nullptr); test_error(err, "Failed to build kernel/program."); err = clGetKernelWorkGroupInfo(kernel, device, CL_KERNEL_WORK_GROUP_SIZE,