[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