[Mesa-dev] [PATCH v4 16/20] clover: Implement clCreateProgramWithILKHR
Pierre Moreau
pierre.morrow at free.fr
Thu Mar 8 00:21:25 UTC 2018
Signed-off-by: Pierre Moreau <pierre.morrow at free.fr>
---
Notes:
Changes in v4: guard parts of the code behind SPIR-V support
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 | 87 +++++++++++++++++++++-
src/gallium/state_trackers/clover/core/program.cpp | 47 ++++++++++--
src/gallium/state_trackers/clover/core/program.hpp | 12 +++
src/gallium/state_trackers/clover/meson.build | 1 +
6 files changed, 146 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 7d57d3f0e9..cc37a008ad 100644
--- a/src/gallium/state_trackers/clover/api/program.cpp
+++ b/src/gallium/state_trackers/clover/api/program.cpp
@@ -21,9 +21,15 @@
//
#include "api/util.hpp"
+#include "compiler/spirv/spirv.h"
#include "core/program.hpp"
+#include "util/u_math.h"
#include "util/u_debug.h"
+#ifdef CLOVER_ALLOW_SPIRV
+#include <spirv-tools/libspirv.hpp>
+#endif
+
#include <sstream>
using namespace clover;
@@ -46,6 +52,60 @@ namespace {
}, objs<allow_empty_tag>(d_devs, num_devs)))
throw error(CL_INVALID_DEVICE);
}
+
+#ifdef CLOVER_ALLOW_SPIRV
+ 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);
+ }
+#endif
+
+ 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;
+
+#ifdef CLOVER_ALLOW_SPIRV
+ 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;
+ }
+#endif
+
+ return il_type;
+ }
}
CLOVER_API cl_program
@@ -129,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,
@@ -185,7 +268,7 @@ clBuildProgram(cl_program d_prog, cl_uint num_devs,
validate_build_common(prog, num_devs, d_devs, valid_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){
@@ -223,7 +306,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 62fa13efbf..9480cfb0b4 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 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
More information about the mesa-dev
mailing list