--- 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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev