[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 &notify) {
+      auto const validator_consumer = [&notify](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 &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 (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