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

EdB edb+mesa at sigluy.net
Sun Dec 14 02:39:37 PST 2014


On Sunday, December 14, 2014 11:31:28 AM EdB wrote:

This one went out by mistake (I forgot to remove -1 option on git send-email).
It's the same as [Patch 7/7]

> ---
>  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;
> +}



More information about the mesa-dev mailing list