[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