[Mesa-dev] [PATCH] clover: add clLinkProgram

EdB edb+mesa at sigluy.net
Sun Dec 14 02:31:28 PST 2014


---
 src/gallium/state_trackers/clover/api/dispatch.cpp |   2 +-
 src/gallium/state_trackers/clover/api/program.cpp  |  31 +++++
 .../state_trackers/clover/core/compiler.hpp        |   6 +
 src/gallium/state_trackers/clover/core/error.hpp   |   7 ++
 src/gallium/state_trackers/clover/core/program.cpp |  56 +++++++++
 src/gallium/state_trackers/clover/core/program.hpp |   3 +
 .../state_trackers/clover/llvm/invocation.cpp      | 129 +++++++++++++++++++++
 7 files changed, 233 insertions(+), 1 deletion(-)

diff --git a/src/gallium/state_trackers/clover/api/dispatch.cpp b/src/gallium/state_trackers/clover/api/dispatch.cpp
index b5a4094..44bff4f 100644
--- a/src/gallium/state_trackers/clover/api/dispatch.cpp
+++ b/src/gallium/state_trackers/clover/api/dispatch.cpp
@@ -123,7 +123,7 @@ namespace clover {
       clCreateImage,
       clCreateProgramWithBuiltInKernels,
       clCompileProgram,
-      NULL, // clLinkProgram
+      clLinkProgram,
       clUnloadPlatformCompiler,
       NULL, // clGetKernelArgInfo
       NULL, // clEnqueueFillBuffer
diff --git a/src/gallium/state_trackers/clover/api/program.cpp b/src/gallium/state_trackers/clover/api/program.cpp
index 1e91da1..be97ae5 100644
--- a/src/gallium/state_trackers/clover/api/program.cpp
+++ b/src/gallium/state_trackers/clover/api/program.cpp
@@ -229,6 +229,37 @@ clCompileProgram(cl_program d_prog, cl_uint num_devs,
    return e.get();
 }
 
+CLOVER_API cl_program
+clLinkProgram (cl_context d_ctx, cl_uint num_devs, const cl_device_id *d_devs,
+               const char *p_opts, cl_uint num_progs, const cl_program *d_progs,
+               void (*pfn_notify) (cl_program, void *), void *user_data,
+               cl_int *r_errcode) try {
+   auto &ctx = obj(d_ctx);
+   auto devs = (d_devs ? objs(d_devs, num_devs) :
+                ref_vector<device>(ctx.devices()));
+   auto opts = (p_opts ? p_opts : "");
+   auto progs = objs(d_progs, num_progs);
+
+   if ((!pfn_notify && user_data))
+         throw error(CL_INVALID_VALUE);
+
+   if (any_of([&](const device &dev) {
+            return !count(dev, ctx.devices());
+         }, objs<allow_empty_tag>(d_devs, num_devs)))
+      throw error(CL_INVALID_DEVICE);
+
+   auto prog = create<program>(ctx, devs, std::vector<module>());
+   if (prog().link(progs, opts))
+      *r_errcode = CL_SUCCESS;
+   else
+      *r_errcode = CL_LINK_PROGRAM_FAILURE;
+
+   return ret_object(prog);
+} catch (error &e) {
+   ret_error(r_errcode, e);
+   return NULL;
+}
+
 CLOVER_API cl_int
 clUnloadCompiler() {
    return CL_SUCCESS;
diff --git a/src/gallium/state_trackers/clover/core/compiler.hpp b/src/gallium/state_trackers/clover/core/compiler.hpp
index 75c7435..168431a 100644
--- a/src/gallium/state_trackers/clover/core/compiler.hpp
+++ b/src/gallium/state_trackers/clover/core/compiler.hpp
@@ -45,6 +45,12 @@ namespace clover {
                                  const compat::string &opts,
                                  compat::string &r_log);
 
+   module link_program_llvm(const compat::vector<module> &modules,
+                              pipe_shader_ir ir,
+                              const compat::string &target,
+                              const compat::string &opts,
+                              compat::string &r_log);
+
    module build_program_tgsi(const compat::string &source);
 }
 
diff --git a/src/gallium/state_trackers/clover/core/error.hpp b/src/gallium/state_trackers/clover/core/error.hpp
index 7b010f1..15a2447 100644
--- a/src/gallium/state_trackers/clover/core/error.hpp
+++ b/src/gallium/state_trackers/clover/core/error.hpp
@@ -71,6 +71,13 @@ namespace clover {
       }
    };
 
+   class link_error : public error {
+   public:
+      link_error(const compat::string &what = "") :
+         error(CL_LINK_PROGRAM_FAILURE, what) {
+      }
+   };
+
    template<typename O>
    class invalid_object_error;
 
diff --git a/src/gallium/state_trackers/clover/core/program.cpp b/src/gallium/state_trackers/clover/core/program.cpp
index a0aeb46..8bece05 100644
--- a/src/gallium/state_trackers/clover/core/program.cpp
+++ b/src/gallium/state_trackers/clover/core/program.cpp
@@ -93,6 +93,48 @@ program::compile(const ref_vector<device> &devs, const char *opts,
 }
 
 bool
+program::link(const ref_vector<program> &progs, const char *opts) {
+   bool ret = true;
+
+   for (auto &d : _devices) {
+      auto &dev = d();
+
+      reset_device(&dev, opts);
+
+      compat::vector<module> mods;
+      mods.reserve(progs.size());
+      for (auto &prog : progs)
+         if (prog.has_linkable(dev))
+            mods.push_back(prog.binary(dev));
+
+      if (mods.size() == 0) {
+         _logs.insert({ &dev,
+"None of the programs contain a compiled binary or library for that device." });
+         ret = false;
+         continue;
+      }
+
+      if (mods.size() != progs.size())
+         throw error(CL_INVALID_OPERATION);
+
+      compat::string log;
+
+      try {
+         auto module = link_program_llvm(mods,
+                                         dev.ir_format(), dev.ir_target(),
+                                         opts, log);
+         _binaries.insert({ &dev, module });
+         _logs.insert({ &dev, log });
+      } catch (const link_error &) {
+         _logs.insert({ &dev, log });
+         ret = false;
+      }
+   }
+
+   return ret;
+}
+
+bool
 program::has_executable() const {
    for (auto &bin : _binaries) {
       if (any_of(type_equals(module::section::text_executable),
@@ -103,6 +145,20 @@ program::has_executable() const {
    return false;
 }
 
+bool
+program::has_linkable(const device &dev) const {
+   const auto bin = _binaries.find(&dev);
+
+   if (bin != _binaries.end()) {
+      const auto &secs = bin->second.secs;
+      if (any_of(type_equals(module::section::text_compiled), secs) ||
+          any_of(type_equals(module::section::text_library), secs))
+         return true;
+   }
+
+   return false;
+}
+
 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 1451c02..19c4420 100644
--- a/src/gallium/state_trackers/clover/core/program.hpp
+++ b/src/gallium/state_trackers/clover/core/program.hpp
@@ -50,8 +50,10 @@ namespace clover {
       void build(const ref_vector<device> &devs, const char *opts);
       void compile(const ref_vector<device> &devs, const char *opts,
                    const header_map &headers);
+      bool link(const ref_vector<program> &progs, const char *opts);
 
       bool has_executable() const;
+      bool has_linkable(const device &dev) const;
       const bool has_source;
       const std::string &source() const;
 
@@ -72,6 +74,7 @@ namespace clover {
 
    private:
       void reset_device(const device *dev, const char *opts);
+
       std::vector<intrusive_ref<device>> _devices;
       std::map<const device *, module> _binaries;
       std::map<const device *, std::string> _logs;
diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp
index 390c625..41d5838 100644
--- a/src/gallium/state_trackers/clover/llvm/invocation.cpp
+++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp
@@ -815,3 +815,132 @@ clover::compile_program_llvm(const compat::string &source,
 
    return m;
 }
+
+module
+clover::link_program_llvm(const compat::vector<module> &modules,
+                             enum pipe_shader_ir ir,
+                             const compat::string &target,
+                             const compat::string &opts,
+                             compat::string &r_log) {
+
+   init_targets();
+   unsigned debug_flags = get_debug_flags();
+
+   std::string options = opts;
+   bool create_library = false;
+   size_t pos = options.find("-create-library");
+   if (pos != std::string::npos) {
+      create_library = true;
+      options.erase(pos, 15);
+   }
+
+   std::string errorlog;
+
+   clang::CompilerInstance c;
+   if (!parse_args(c, options))
+      throw error(CL_INVALID_LINKER_OPTIONS);
+
+
+   size_t processor_str_len = std::string(target.begin()).find_first_of("-");
+   std::string processor(target.begin(), 0, processor_str_len);
+   std::string triple(target.begin(), processor_str_len + 1,
+                      target.size() - processor_str_len - 1);
+   c.getLangOpts().NoBuiltin = true;
+   c.getTargetOpts().Triple = triple;
+   c.getTargetOpts().CPU = processor;
+
+   clang::LangAS::Map address_spaces;
+   llvm::LLVMContext llvm_ctx;
+
+   llvm_ctx.setDiagnosticHandler(diagnostic_handler, &r_log);
+
+   llvm::Module linked_mod("linked", llvm_ctx);
+   llvm::Linker linker(&linked_mod);
+
+   for (compat::vector<module>::const_iterator it = modules.begin();
+                                                    it != modules.end(); ++it) {
+      const module &mod = *it;
+      std::string s = std::string(mod.secs[0].data.begin(),
+                                  mod.secs[0].data.size());
+
+      llvm::ErrorOr<llvm::Module*> m = llvm::parseBitcodeFile(
+                                 llvm::MemoryBuffer::getMemBuffer(s), llvm_ctx);
+      if (!m) {
+         r_log = m.getError().message();
+         throw error(CL_INVALID_PROGRAM);
+      }
+
+      if (linker.linkInModule(*m, &errorlog)) {
+         r_log = errorlog;
+         throw link_error();
+      }
+
+#if HAVE_LLVM >= 0x0306
+      buffer.release();
+#endif
+   }
+
+   module m;
+   std::vector<llvm::Function *> kernels;
+
+   //optimize
+   if (!create_library)
+      find_kernels(&linked_mod, kernels);
+
+   unsigned optimization_level = c.getCodeGenOpts().OptimizationLevel;
+   optimize(&linked_mod, optimization_level, kernels);
+
+   if (debug_flags & DBG_LLVM) {
+      std::string log;
+      llvm::raw_string_ostream s_log(log);
+      linked_mod.print(s_log, NULL);
+      s_log.flush();
+      debug_log(log, ".ll");
+    }
+
+    if (create_library) {
+      //serialize for later use
+      llvm::SmallVector<char, 1024> llvm_bitcode;
+      llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode);
+      llvm::BitstreamWriter writer(llvm_bitcode);
+      llvm::WriteBitcodeToFile(&linked_mod, bitcode_ostream);
+      bitcode_ostream.flush();
+
+      std::string data(llvm_bitcode.begin(), llvm_bitcode.end());
+      m.secs.push_back(module::section(0, module::section::text_library,
+                                       data.size(), data));
+
+   } else {
+
+      llvm::raw_string_ostream s_log(errorlog);
+      clang::TextDiagnosticPrinter *diag = new clang::TextDiagnosticPrinter(
+                                                 s_log, &c.getDiagnosticOpts());
+      c.createDiagnostics(diag);
+
+      // Get address spaces map to be able to find kernel argument address space
+      std::shared_ptr<clang::TargetOptions> target_opts(&c.getTargetOpts());
+      clang::TargetInfo *target_info = clang::TargetInfo::CreateTargetInfo(
+                                               c.getDiagnostics(), target_opts);
+      memcpy(address_spaces, target_info->getAddressSpaceMap(),
+                                                        sizeof(address_spaces));
+
+      // Build the clover::module
+      switch (ir) {
+         case PIPE_SHADER_IR_TGSI:
+            break; //not supported
+         case PIPE_SHADER_IR_LLVM:
+            m = build_module_llvm(&linked_mod, kernels, address_spaces);
+            break;
+         case PIPE_SHADER_IR_NATIVE: {
+            std::vector<char> code = compile_native(&linked_mod,
+                               triple, processor, debug_flags & DBG_ASM, r_log);
+            m = build_module_native(code, &linked_mod, kernels, address_spaces,
+                                    r_log);
+            break;
+         }
+      }
+
+   }
+
+   return m;
+}
-- 
2.2.0



More information about the mesa-dev mailing list