[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 &notify) {
+
+      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