diff --git a/test_common/harness/cl_offline_compiler-interface.txt b/test_common/harness/cl_offline_compiler-interface.txt new file mode 100644 index 00000000..30ab1822 --- /dev/null +++ b/test_common/harness/cl_offline_compiler-interface.txt @@ -0,0 +1,25 @@ +The cl_offline_compiler program used for offline compilation must +implement the following interface. + + usage: cl_offline_compiler --source FILE --output FILE + --cl-device-info FILE --mode MODE + -- [BUILD_OPTIONS [BUILD_OPTIONS ...]] + + positional arguments: + BUILD_OPTIONS additional options to pass to the compiler + + optional arguments: + --source FILE OpenCL C source file to compile + --output FILE SPIR-V or binary file to create + --cl-device-info FILE OpenCL device info file + --mode compilation mode (spir-v or binary) + +The --cl-device-info file is a list of KEY=VALUE pairs containing device +information relevant to the mode of offline compilation in question. +It is of the following form: + + # OpenCL device info affecting offline compilation: + CL_DEVICE_ADDRESS_BITS=<32|64> + CL_DEVICE_EXTENSIONS="" + CL_DEVICE_IL_VERSION="" + CL_DEVICE_VERSION="OpenCL " diff --git a/test_common/harness/deviceInfo.cpp b/test_common/harness/deviceInfo.cpp index 605e326c..aeb5607b 100644 --- a/test_common/harness/deviceInfo.cpp +++ b/test_common/harness/deviceInfo.cpp @@ -76,3 +76,15 @@ char *alloc_and_get_device_extensions_string(cl_device_id device) { return (char *) alloc_and_get_device_info(device, CL_DEVICE_EXTENSIONS, "extensions string"); } + +/* Returns a newly allocated C string containing the supported IL version(s) for a device. */ +char *alloc_and_get_device_il_version_string(cl_device_id device) +{ + return (char *) alloc_and_get_device_info(device, CL_DEVICE_IL_VERSION, "IL version string"); +} + +/* Returns a newly allocated C string containing the supported OpenCL version for a device. */ +char *alloc_and_get_device_version_string(cl_device_id device) +{ + return (char *) alloc_and_get_device_info(device, CL_DEVICE_VERSION, "version string"); +} diff --git a/test_common/harness/deviceInfo.h b/test_common/harness/deviceInfo.h index c653bd3b..779453f7 100644 --- a/test_common/harness/deviceInfo.h +++ b/test_common/harness/deviceInfo.h @@ -31,6 +31,12 @@ int is_extension_available(cl_device_id device, const char *extensionName); /* Returns a newly allocated C string containing the supported extensions list for a device. */ char *alloc_and_get_device_extensions_string(cl_device_id device); +/* Returns a newly allocated C string containing the supported IL version(s) for a device. */ +char *alloc_and_get_device_il_version_string(cl_device_id device); + +/* Returns a newly allocated C string containing the supported OpenCL version for a device. */ +char *alloc_and_get_device_version_string(cl_device_id device); + #ifdef __cplusplus } #endif // __cplusplus diff --git a/test_common/harness/kernelHelpers.c b/test_common/harness/kernelHelpers.c index 3496c323..3b3724f6 100644 --- a/test_common/harness/kernelHelpers.c +++ b/test_common/harness/kernelHelpers.c @@ -39,6 +39,8 @@ std::string slash = "\\"; std::string slash = "/"; #endif +static cl_int get_first_device_id(const cl_context context, cl_device_id &device); + std::string get_file_name(const std::string &baseName, int index, const std::string &extension) { std::ostringstream fileName; @@ -231,6 +233,22 @@ static std::string get_offline_compilation_file_type_str(const CompilationMode c } } +static std::string get_compilation_mode_str(const CompilationMode compilationMode) +{ + switch (compilationMode) + { + default: + assert(0 && "Invalid compilation mode"); + abort(); + case kOnline: + return "online"; + case kBinary: + return "binary"; + case kSpir_v: + return "spir-v"; + } +} + #ifdef KHRONOS_OFFLINE_COMPILER static std::string get_khronos_compiler_command(const cl_uint device_address_space_size, const bool openclCXX, @@ -281,82 +299,118 @@ static std::string get_khronos_compiler_command(const cl_uint device_address_spa } #endif // KHRONOS_OFFLINE_COMPILER +static cl_int get_cl_device_info_str(const cl_device_id device, const cl_uint device_address_space_size, + const CompilationMode compilationMode, std::string &clDeviceInfo) +{ + char *extensionsString = alloc_and_get_device_extensions_string(device); + if ( NULL == extensionsString ) + { + /* An error message will have already been printed by alloc_and_get_device_info(), + * so we can just return, here. */ + return -1; + } + + BufferOwningPtr extensionsStringBuf(extensionsString); + + char *versionString = alloc_and_get_device_version_string(device); + if ( NULL == versionString ) + { + /* An error message will have already been printed by alloc_and_get_device_info(), + * so we can just return, here. */ + return -1; + } + + BufferOwningPtr versionStringBuf(versionString); + + std::ostringstream clDeviceInfoStream; + std::string file_type = get_offline_compilation_file_type_str(compilationMode); + clDeviceInfoStream << "# OpenCL device info affecting " << file_type << " offline compilation:" << std::endl + << "CL_DEVICE_ADDRESS_BITS=" << device_address_space_size << std::endl + << "CL_DEVICE_EXTENSIONS=\"" << extensionsString << "\"" << std::endl; + /* We only need the device's supported IL version(s) when compiling IL + * that will be loaded with clCreateProgramWithIL() */ + if (compilationMode == kSpir_v) + { + char *ilVersionString = alloc_and_get_device_il_version_string(device); + if ( NULL == ilVersionString ) + { + /* An error message will have already been printed by alloc_and_get_device_info(), + * so we can just return, here. */ + return -1; + } + + BufferOwningPtr versionStringBuf(ilVersionString); + + clDeviceInfoStream << "CL_DEVICE_IL_VERSION=\"" << ilVersionString << "\"" << std::endl; + } + clDeviceInfoStream << "CL_DEVICE_VERSION=\"" << versionString << "\"" << std::endl; + + clDeviceInfo = clDeviceInfoStream.str(); + return CL_SUCCESS; +} + +static int write_cl_device_info(const cl_device_id device, const cl_uint device_address_space_size, + const CompilationMode compilationMode, std::string &clDeviceInfoFilename) +{ + std::string clDeviceInfo; + int error = get_cl_device_info_str(device, device_address_space_size, compilationMode, clDeviceInfo); + if (error != CL_SUCCESS) + { + return error; + } + + cl_uint crc = crc32(clDeviceInfo.data(), clDeviceInfo.size()); + + /* Get the filename for the clDeviceInfo file. + * Note: the file includes the hash on its content, so it is usually unnecessary to delete it. */ + std::ostringstream clDeviceInfoFilenameStream; + clDeviceInfoFilenameStream << gCompilationCachePath << slash << "clDeviceInfo-"; + clDeviceInfoFilenameStream << std::hex << std::setfill('0') << std::setw(8) << crc << ".txt"; + + clDeviceInfoFilename = clDeviceInfoFilenameStream.str(); + + if ((size_t) get_file_size(clDeviceInfoFilename) == clDeviceInfo.size()) + { + /* The CL device info file has already been created. + * Nothing to do. */ + return 0; + } + + /* The file does not exist or its length is not as expected. Create/overwrite it. */ + std::ofstream ofs(clDeviceInfoFilename); + if (!ofs.good()) + { + log_info("OfflineCompiler: can't create CL device info file: %s\n", clDeviceInfoFilename.c_str()); + return -1; + } + ofs << clDeviceInfo; + ofs.close(); + + return CL_SUCCESS; +} + static std::string get_offline_compilation_command(const cl_uint device_address_space_size, const CompilationMode compilationMode, const std::string &bOptions, const std::string &sourceFilename, - const std::string &outputFilename) + const std::string &outputFilename, + const std::string &clDeviceInfoFilename) { - std::ostringstream size_t_width_stream; - size_t_width_stream << device_address_space_size; - std::string size_t_width_str = size_t_width_stream.str(); + std::ostringstream wrapperOptions; - // set output type and default script - std::string outputTypeStr; - std::string defaultScript; - if (compilationMode == kBinary) + wrapperOptions << gCompilationProgram + << " --mode=" << get_compilation_mode_str(compilationMode) + << " --source=" << sourceFilename + << " --output=" << outputFilename + << " --cl-device-info=" << clDeviceInfoFilename; + + if (bOptions != "") { - outputTypeStr = "binary"; - #if defined(_WIN32) - defaultScript = "..\\build_script_binary.py "; - #else - defaultScript = "../build_script_binary.py "; - #endif - } - else if (compilationMode == kSpir_v) - { - outputTypeStr = "spir_v"; - #if defined(_WIN32) - defaultScript = "..\\build_script_spirv.py "; - #else - defaultScript = "../build_script_spirv.py "; - #endif + // Add build options passed to this function + wrapperOptions << " -- " << bOptions; } - // set script arguments - std::string scriptArgs = sourceFilename + " " + outputFilename + " " + size_t_width_str + " " + outputTypeStr; - - if (!bOptions.empty()) - { - //search for 2.0 build options - std::string oclVersion; - std::string buildOptions20 = "-cl-std=CL2.0"; - std::size_t found = bOptions.find(buildOptions20); - - if (found != std::string::npos) - oclVersion = "20"; - else - oclVersion = "12"; - - std::string bOptionsWRemovedStd20 = bOptions; - - std::string::size_type i = bOptions.find(buildOptions20); - - if (i != std::string::npos) - bOptionsWRemovedStd20.erase(i, buildOptions20.length()); - - //remove space before -cl-std=CL2.0 if it was first build option - size_t spacePos = bOptionsWRemovedStd20.find_last_of(" \t\r\n", i); - if (spacePos != std::string::npos && i == 0) - bOptionsWRemovedStd20.erase(spacePos, sizeof(char)); - - //remove space after -cl-std=CL2.0 - spacePos = bOptionsWRemovedStd20.find_first_of(" \t\r\n", i - 1); - if (spacePos != std::string::npos) - bOptionsWRemovedStd20.erase(spacePos, sizeof(char)); - - if (!bOptionsWRemovedStd20.empty()) - scriptArgs += " " + oclVersion + " \"" + bOptionsWRemovedStd20 + "\""; - else - scriptArgs += " " + oclVersion; - } - else - scriptArgs += " 12"; - - // set script command line - std::string scriptToRunString = defaultScript + scriptArgs; - - return scriptToRunString; + return wrapperOptions.str(); } static int invoke_offline_compiler(const cl_device_id device, @@ -385,8 +439,23 @@ static int invoke_offline_compiler(const cl_device_id device, } else { + std::string clDeviceInfoFilename; + + // See cl_offline_compiler-interface.txt for a description of the + // format of the CL device information file generated below, and + // the internal command line interface for invoking the offline + // compiler. + + cl_int err = write_cl_device_info(device, device_address_space_size, compilationMode, + clDeviceInfoFilename); + if (err != CL_SUCCESS) + { + log_error("Failed writing CL device info file\n"); + return err; + } + runString = get_offline_compilation_command(device_address_space_size, compilationMode, bOptions, - sourceFilename, outputFilename); + sourceFilename, outputFilename, clDeviceInfoFilename); } // execute script diff --git a/test_common/harness/parseParameters.cpp b/test_common/harness/parseParameters.cpp index 2051d0b3..82a15fd7 100644 --- a/test_common/harness/parseParameters.cpp +++ b/test_common/harness/parseParameters.cpp @@ -27,9 +27,12 @@ using namespace std; +#define DEFAULT_COMPILATION_PROGRAM "cl_offline_compiler" + CompilationMode gCompilationMode = kOnline; CompilationCacheMode gCompilationCacheMode = kCacheModeCompileIfAbsent; std::string gCompilationCachePath = "."; +std::string gCompilationProgram = DEFAULT_COMPILATION_PROGRAM; void helpInfo () { @@ -47,6 +50,8 @@ void helpInfo () " force-read Force reading from the cache\n" " overwrite Disable reading from the cache\n" " --compilation-cache-path Path for offline compiler output and CL source\n" + " --compilation-program Program to use for offline compilation,\n" + " defaults to " DEFAULT_COMPILATION_PROGRAM "\n" "\n"); } @@ -158,6 +163,20 @@ int parseCustomParam (int argc, const char *argv[], const char *ignore) return -1; } } + else if (!strcmp(argv[i], "--compilation-program")) + { + delArg++; + if ((i + 1) < argc) + { + delArg++; + gCompilationProgram = argv[i + 1]; + } + else + { + log_error("Program argument for --compilation-program was not specified.\n"); + return -1; + } + } //cleaning parameters from argv tab for (int j = i; j < argc - delArg; j++) diff --git a/test_common/harness/parseParameters.h b/test_common/harness/parseParameters.h index 241c0708..4eee0987 100644 --- a/test_common/harness/parseParameters.h +++ b/test_common/harness/parseParameters.h @@ -36,6 +36,7 @@ enum CompilationCacheMode extern CompilationMode gCompilationMode; extern CompilationCacheMode gCompilationCacheMode; extern std::string gCompilationCachePath; +extern std::string gCompilationProgram; extern int parseCustomParam (int argc, const char *argv[], const char *ignore = 0 ); diff --git a/test_conformance/build_script_binary.py b/test_conformance/build_script_binary.py deleted file mode 100644 index 276cfb92..00000000 --- a/test_conformance/build_script_binary.py +++ /dev/null @@ -1,7 +0,0 @@ -# Script parameters: -# 1 - input file -# 2 - output file -# 3 - architecture: 32 or 64 -# 4 - one of the strings: binary, source, spir_v -# 5 - OpenCL version: 12, 20 -# 6 - build options diff --git a/test_conformance/build_script_spirv.py b/test_conformance/build_script_spirv.py deleted file mode 100644 index 86193b33..00000000 --- a/test_conformance/build_script_spirv.py +++ /dev/null @@ -1,43 +0,0 @@ -# Script parameters: -# 1 - input file -# 2 - output file -# 3 - architecture: 32 or 64 -# 4 - one of the strings: binary, source, spir_v -# 5 - OpenCL version: 12, 20 -# 6 - build options - -import os -import sys - -if len(sys.argv)<5: - print 'Usage: "build_script_spirv.py [build_options]"' - exit(1) - -input_file = sys.argv[1] -output_file = sys.argv[2] -arch = sys.argv[3] -output_type = sys.argv[4] -ocl_version = sys.argv[5] -build_options = '' - -if len(sys.argv) == 5: - build_options = sys.argv[6] - -if arch == '32': - arch_string = '' - spir_arch = '__i386__' -else: - arch_string = '64' - spir_arch = '__x86_64__' - -if ocl_version == '20': - oclc_version = '200' - spir_version = '2.0' -else: - oclc_version = '120' - spir_version = '1.2' - -command = '%LLVMPATH%\\bin\\clang.exe -cc1 -include headers\\opencl_SPIR-' + spir_version + '.h -cl-std=CL' + spir_version +' -D__OPENCL_C_VERSION__=' + oclc_version + ' -fno-validate-pch -D__OPENCL_VERSION__=' + oclc_version + ' -x cl -cl-kernel-arg-info -O0 -emit-llvm-bc -triple spir' + arch_string + '-unknown-unknown -D' + spir_arch + ' -Dcl_khr_3d_image_writes -Dcl_khr_byte_addressable_store -Dcl_khr_d3d10_sharing -Dcl_khr_d3d11_sharing -Dcl_khr_depth_images -Dcl_khr_dx9_media_sharing -Dcl_khr_fp64 -Dcl_khr_global_int32_base_atomics -Dcl_khr_global_int32_extended_atomics -Dcl_khr_gl_depth_images -Dcl_khr_gl_event -Dcl_khr_gl_msaa_sharing -Dcl_khr_gl_sharing -Dcl_khr_icd -Dcl_khr_image2d_from_buffer -Dcl_khr_local_int32_base_atomics -Dcl_khr_local_int32_extended_atomics -Dcl_khr_mipmap_image -Dcl_khr_mipmap_image_writes -Dcl_khr_fp16 ' + build_options + ' -Dcl_khr_spir ' + input_file + ' -o intermediate.spir' -os.system(command) -command = '%LLVMPATH%\\bin\\llvm-spirv.exe intermediate.spir -o ' + output_file -os.system(command) \ No newline at end of file diff --git a/test_conformance/generate_spirv_offline.py b/test_conformance/generate_spirv_offline.py index dd37af5a..3612319d 100755 --- a/test_conformance/generate_spirv_offline.py +++ b/test_conformance/generate_spirv_offline.py @@ -4,19 +4,17 @@ from __future__ import print_function import sys import os -import re import traceback if len(sys.argv) != 3: - print('Usage: "generate_spirv_offline.py <32|64>"') + print('Usage: "generate_spirv_offline.py "') exit(1) compilation_cache_dir = sys.argv[1] -arch = sys.argv[2] +cl_device_info_filename = sys.argv[2] def generate_spirv(): print("Generating SPIR-V files") - ocl_version = '12'; build_options = '' if os.path.exists(compilation_cache_dir): @@ -24,23 +22,18 @@ def generate_spirv(): for file in files: if file.endswith('.cl'): options_file_name = file[:-2] + "options" - ocl_version = '12' if os.path.exists(os.path.join(root, options_file_name)): - optFile = open (os.path.join(root, options_file_name), 'rU') - for line in optFile: - if re.search("-cl-std=CL2.0", line): - ocl_version = '20' - build_options = re.sub("-cl-std=CL2.0", "", line) + optFile = open (os.path.join(root, options_file_name), 'r') + build_options = optFile.readline().strip() print(build_options) source_filename = os.path.join(root, file) - output_filename = os.path.join(root, file[:-2]) + "spv" + arch + output_filename = os.path.join(root, file[:-2]) + "spv" - command_line = (".\\build_script_spirv.py" + - " " + source_filename + - " " + output_filename + - " " + arch + - " spir_v" + - " " + ocl_version + + command_line = ("cl_offline_compiler" + + " --source=" + source_filename + + " --output=" + output_filename + + " --cl-device-info=" + cl_device_info_filename + + " --mode=spir-v -- " + '"' + build_options + '"') print(command_line) os.system(command_line)