[Mesa-dev] [PATCH v10 16/20] clover: Implement clCreateProgramWithILKHR
Pierre Moreau
pierre.morrow at free.fr
Tue Jan 8 21:11:05 UTC 2019
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.morrow at 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
More information about the mesa-dev
mailing list