Signed-off-by: Pierre Moreau <pierre.mor...@free.fr> --- Notes: v3: * 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.
src/gallium/state_trackers/clover/Makefile.am | 6 +- src/gallium/state_trackers/clover/api/dispatch.hpp | 4 ++ src/gallium/state_trackers/clover/api/program.cpp | 81 +++++++++++++++++++++- src/gallium/state_trackers/clover/core/program.cpp | 46 +++++++++--- src/gallium/state_trackers/clover/core/program.hpp | 12 ++++ src/gallium/state_trackers/clover/meson.build | 1 + 6 files changed, 139 insertions(+), 11 deletions(-) diff --git a/src/gallium/state_trackers/clover/Makefile.am b/src/gallium/state_trackers/clover/Makefile.am index 35ee092f3f..9ae053ac5e 100644 --- a/src/gallium/state_trackers/clover/Makefile.am +++ b/src/gallium/state_trackers/clover/Makefile.am @@ -46,11 +46,15 @@ libclllvm_la_SOURCES = $(LLVM_SOURCES) libclover_la_CXXFLAGS = \ $(CXX11_CXXFLAGS) \ $(CLOVER_STD_OVERRIDE) \ - $(VISIBILITY_CXXFLAGS) + $(VISIBILITY_CXXFLAGS) \ + $(SPIRV_TOOLS_CFLAGS) libclover_la_LIBADD = \ libclllvm.la +libclover_la_LDFLAGS = \ + $(SPIRV_TOOLS_LIBS) + libclover_la_SOURCES = $(CPP_SOURCES) EXTRA_DIST = Doxyfile meson.build diff --git a/src/gallium/state_trackers/clover/api/dispatch.hpp b/src/gallium/state_trackers/clover/api/dispatch.hpp index 60fb75a146..3d5fc7bf47 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 022ddbdbcc..c618557adf 100644 --- a/src/gallium/state_trackers/clover/api/program.cpp +++ b/src/gallium/state_trackers/clover/api/program.cpp @@ -21,9 +21,13 @@ // #include "api/util.hpp" +#include "compiler/spirv/spirv.h" #include "core/program.hpp" +#include "util/u_math.h" #include "util/u_debug.h" +#include <spirv-tools/libspirv.hpp> + #include <sstream> using namespace clover; @@ -52,6 +56,56 @@ namespace { return devs; } + + bool + is_valid_spirv(const uint32_t *binary, size_t length, + const context::notify_action ¬ify) { + auto const validator_consumer = [¬ify](spv_message_level_t level, + const char * /* source */, + const spv_position_t &position, + const char *message) { + if (!notify) + return; + + std::string str_level; + switch (level) { +#define LVL2STR(lvl) case SPV_MSG_##lvl: str_level = std::string(#lvl) + LVL2STR(FATAL); + LVL2STR(INTERNAL_ERROR); + LVL2STR(ERROR); + LVL2STR(WARNING); + LVL2STR(INFO); + LVL2STR(DEBUG); +#undef LVL2STR + } + const std::string log = "[" + str_level + "] At word No." + + std::to_string(position.index) + ": \"" + + message + "\""; + notify(log.c_str()); + }; + + spvtools::SpirvTools spvTool(SPV_ENV_OPENCL_1_2); + spvTool.SetMessageConsumer(validator_consumer); + + return spvTool.Validate(binary, length); + } + + enum program::il_type + identify_and_validate_il(const void *il, size_t length, + const context::notify_action ¬ify) { + + enum program::il_type il_type = program::il_type::none; + + const uint32_t *stream = reinterpret_cast<const uint32_t*>(il); + if (stream[0] == SpvMagicNumber || + util_bswap32(stream[0]) == SpvMagicNumber) { + if (!is_valid_spirv(stream, length / 4u, notify)) + throw error(CL_INVALID_VALUE); + il_type = program::il_type::spirv; + } + + return il_type; + } } CLOVER_API cl_program @@ -135,6 +189,29 @@ 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); + + const enum program::il_type il_type = identify_and_validate_il(il, length, + 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, @@ -189,7 +266,7 @@ clBuildProgram(cl_program d_prog, cl_uint num_devs, const auto opts = std::string(p_opts ? p_opts : "") + " " + debug_get_option("CLOVER_EXTRA_BUILD_OPTIONS", ""); - 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){ @@ -225,7 +302,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 1ad58c2be5..c304f51c54 100644 --- a/src/gallium/state_trackers/clover/core/program.cpp +++ b/src/gallium/state_trackers/clover/core/program.cpp @@ -25,26 +25,47 @@ 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.ir_target(), + opts, log); + else if (prog.il_type() == program::il_type::spirv) + return llvm::compile_from_spirv(prog.il(), dev, log); + 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 +73,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.ir_target(), 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; @@ -86,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 05964e78a7..ce0607982d 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; }; } diff --git a/src/gallium/state_trackers/clover/meson.build b/src/gallium/state_trackers/clover/meson.build index bffd0df11d..4e34348574 100644 --- a/src/gallium/state_trackers/clover/meson.build +++ b/src/gallium/state_trackers/clover/meson.build @@ -111,5 +111,6 @@ libclover = static_library( clover_files, include_directories : clover_incs, cpp_args : [clover_cpp_args, cpp_vis_args], + dependencies : [dep_spirv_tools], link_with : [libclllvm], ) -- 2.16.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev