Changes since: * v4: - Use is_binary_spirv and is_valid_spirv from the SPIR-V backend; - Drop the SPIRV-Tools and llvm-spirv dependencies on clover. * v3: guard parts of the code behind SPIR-V support * v2: - Remove the const on the length argument to CreateProgramWithILKHR (Francisco Jerez) - Capitalize comment (Francisco Jerez); - Store the IL as a std::vector instead of a pointer + size (Francisco Jerez); - Remove the destructor, due to previous change; - Remove endianness conversion, as already performed later on (Francisco Jerez); - Introduce a free function for compile_program, which calls the right compile function based on the IR format (Francisco Jerez); - Add dependency on SPIRV-Tools, as we validate the SPIR-V module fed to clCreateProgramWithILKHR; - Introduce an enum for representing which IL is stored in program; - Correctly initialise the devices associated to a program created from clCreateProgramWithILKHR; - Introduce free functions for validating the SPIR-V binary, and detecting the IL used in the binary fed to clCreateProgramWithILKHR.
Signed-off-by: Pierre Moreau <pierre.mor...@free.fr> --- .../state_trackers/clover/api/dispatch.hpp | 4 ++ .../state_trackers/clover/api/program.cpp | 60 ++++++++++++++++++- .../state_trackers/clover/core/program.cpp | 47 ++++++++++++--- .../state_trackers/clover/core/program.hpp | 12 ++++ 4 files changed, 113 insertions(+), 10 deletions(-) diff --git a/src/gallium/state_trackers/clover/api/dispatch.hpp b/src/gallium/state_trackers/clover/api/dispatch.hpp index 84b992af9ba..dc9c94a5408 100644 --- a/src/gallium/state_trackers/clover/api/dispatch.hpp +++ b/src/gallium/state_trackers/clover/api/dispatch.hpp @@ -974,6 +974,10 @@ namespace clover { cl_int IcdGetPlatformIDsKHR(cl_uint num_entries, cl_platform_id *rd_platforms, cl_uint *rnum_platforms); + + cl_program + CreateProgramWithILKHR(cl_context d_ctx, const void *il, + size_t length, cl_int *r_errcode); } #endif diff --git a/src/gallium/state_trackers/clover/api/program.cpp b/src/gallium/state_trackers/clover/api/program.cpp index acfbe560445..00b252e12b4 100644 --- a/src/gallium/state_trackers/clover/api/program.cpp +++ b/src/gallium/state_trackers/clover/api/program.cpp @@ -22,6 +22,7 @@ #include "api/util.hpp" #include "core/program.hpp" +#include "spirv/invocation.hpp" #include "util/u_debug.h" #include <sstream> @@ -45,6 +46,26 @@ namespace { }, objs<allow_empty_tag>(d_devs, num_devs))) throw error(CL_INVALID_DEVICE); } + + enum program::il_type + identify_and_validate_il(const void *il, size_t length, + const std::string &opencl_version, + const context::notify_action ¬ify) { + + enum program::il_type il_type = program::il_type::none; + +#ifdef CLOVER_ALLOW_SPIRV + const uint32_t *stream = reinterpret_cast<const uint32_t*>(il); + if (spirv::is_binary_spirv(reinterpret_cast<const char*>(il), length)) { + if (!spirv::is_valid_spirv(stream, length / 4u, opencl_version, + notify)) + throw error(CL_INVALID_VALUE); + il_type = program::il_type::spirv; + } +#endif + + return il_type; + } } CLOVER_API cl_program @@ -128,6 +149,41 @@ clCreateProgramWithBinary(cl_context d_ctx, cl_uint n, return NULL; } +cl_program +clover::CreateProgramWithILKHR(cl_context d_ctx, const void *il, + size_t length, cl_int *r_errcode) try { + auto &ctx = obj(d_ctx); + + if (!il || !length) + throw error(CL_INVALID_VALUE); + + // Compute the highest OpenCL version supported by all devices associated to + // the context. That is the version used for validating the SPIR-V binary. + std::string min_opencl_version; + for (const device &dev : ctx.devices()) { + const std::string opencl_version = dev.device_version(); + if (min_opencl_version.empty()) + min_opencl_version = opencl_version; + else if (opencl_version < min_opencl_version) + min_opencl_version = opencl_version; + } + + const enum program::il_type il_type = identify_and_validate_il(il, length, + min_opencl_version, + ctx.notify); + + if (il_type == program::il_type::none) + throw error(CL_INVALID_VALUE); + + // Initialize a program object with it. + ret_error(r_errcode, CL_SUCCESS); + return new program(ctx, reinterpret_cast<const char*>(il), length, il_type); + +} catch (error &e) { + ret_error(r_errcode, e); + return NULL; +} + CLOVER_API cl_program clCreateProgramWithBuiltInKernels(cl_context d_ctx, cl_uint n, const cl_device_id *d_devs, @@ -183,7 +239,7 @@ clBuildProgram(cl_program d_prog, cl_uint num_devs, validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data); - if (prog.has_source) { + if (prog.has_source || prog.has_il) { prog.compile(devs, opts); prog.link(devs, opts, { prog }); } else if (any_of([&](const device &dev){ @@ -220,7 +276,7 @@ clCompileProgram(cl_program d_prog, cl_uint num_devs, if (bool(num_headers) != bool(header_names)) throw error(CL_INVALID_VALUE); - if (!prog.has_source) + if (!prog.has_source && !prog.has_il) throw error(CL_INVALID_OPERATION); for_each([&](const char *name, const program &header) { diff --git a/src/gallium/state_trackers/clover/core/program.cpp b/src/gallium/state_trackers/clover/core/program.cpp index 62fa13efbf9..9480cfb0b40 100644 --- a/src/gallium/state_trackers/clover/core/program.cpp +++ b/src/gallium/state_trackers/clover/core/program.cpp @@ -25,26 +25,48 @@ using namespace clover; +namespace { + module + compile_program(const program &prog, const device &dev, + const std::string &opts, const header_map &headers, + std::string &log) { + if (!prog.source().empty()) + return llvm::compile_program(prog.source(), headers, dev, opts, log); +#ifdef CLOVER_ALLOW_SPIRV + else if (prog.il_type() == program::il_type::spirv) + return llvm::compile_from_spirv(prog.il(), dev, log); +#endif + else + throw error(CL_INVALID_VALUE); + } +} // end of anonymous namespace + program::program(clover::context &ctx, const std::string &source) : - has_source(true), context(ctx), _devices(ctx.devices()), _source(source), - _kernel_ref_counter(0) { + has_source(true), has_il(false), context(ctx), _devices(ctx.devices()), + _source(source), _kernel_ref_counter(0), _il(), _il_type(il_type::none) { } program::program(clover::context &ctx, const ref_vector<device> &devs, const std::vector<module> &binaries) : - has_source(false), context(ctx), - _devices(devs), _kernel_ref_counter(0) { + has_source(false), has_il(false), context(ctx), _devices(devs), + _kernel_ref_counter(0), _il(), _il_type(il_type::none) { for_each([&](device &dev, const module &bin) { _builds[&dev] = { bin }; }, devs, binaries); } +program::program(clover::context &ctx, const char *il, size_t length, + enum il_type il_type) : + has_source(false), has_il(true), context(ctx), _devices(ctx.devices()), + _kernel_ref_counter(0), _il(il, il + length), _il_type(il_type) { +} + void program::compile(const ref_vector<device> &devs, const std::string &opts, const header_map &headers) { - if (has_source) { + if (has_source || has_il) { _devices = devs; for (auto &dev : devs) { @@ -52,9 +74,8 @@ program::compile(const ref_vector<device> &devs, const std::string &opts, try { assert(dev.ir_format() == PIPE_SHADER_IR_NATIVE); - const module m = llvm::compile_program(_source, headers, dev, opts, - log); - _builds[&dev] = { m, opts, log }; + _builds[&dev] = { compile_program(*this, dev, opts, headers, log), + opts, log }; } catch (...) { _builds[&dev] = { module(), opts, log }; throw; @@ -85,6 +106,16 @@ program::link(const ref_vector<device> &devs, const std::string &opts, } } +const std::vector<char> & +program::il() const { + return _il; +} + +enum program::il_type +program::il_type() const { + return _il_type; +} + const std::string & program::source() const { return _source; diff --git a/src/gallium/state_trackers/clover/core/program.hpp b/src/gallium/state_trackers/clover/core/program.hpp index 05964e78a79..ce0607982d1 100644 --- a/src/gallium/state_trackers/clover/core/program.hpp +++ b/src/gallium/state_trackers/clover/core/program.hpp @@ -38,11 +38,17 @@ namespace clover { evals, const std::vector<intrusive_ref<device>> &> device_range; public: + enum class il_type { none, llvm_ir, spirv }; + program(clover::context &ctx, const std::string &source); program(clover::context &ctx, const ref_vector<device> &devs = {}, const std::vector<module> &binaries = {}); + program(clover::context &ctx, + const char *il, + size_t length, + enum il_type il_type); program(const program &prog) = delete; program & @@ -56,6 +62,10 @@ namespace clover { const bool has_source; const std::string &source() const; + const bool has_il; + const std::vector<char> &il() const; + enum il_type il_type() const; + device_range devices() const; struct build { @@ -85,6 +95,8 @@ namespace clover { std::map<const device *, struct build> _builds; std::string _source; ref_counter _kernel_ref_counter; + std::vector<char> _il; + enum il_type _il_type; }; } -- 2.20.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev