Page MenuHomePhabricator
Paste P111

Old patch for clCreateProgramWithSource() support
ActivePublic

Authored by pmoreau on Sep 20 2017, 1:26 AM.
commit b14a3239296de45f72adc497141a1ff5fb2400e3
Author: Pierre Moreau <pierre.morrow@free.fr>
Date: Sat Apr 23 22:15:02 2016 +0200
[HACK] clover: `clCreateProgramWithSource` using SPIR-V
diff --git a/configure.ac b/configure.ac
index aea5890039..127a70d5a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2189,6 +2189,9 @@ if test "x$enable_gallium_llvm" = xyes; then
LLVM_COMPONENTS="${LLVM_COMPONENTS} all-targets ipo linker instrumentation"
LLVM_COMPONENTS="${LLVM_COMPONENTS} irreader option objcarcopts profiledata"
fi
+ if test "x$enable_nouveau_llvm_compiler" = xyes; then
+ LLVM_COMPONENTS="${LLVM_COMPONENTS} spirvlib"
+ fi
DEFINES="${DEFINES} -DHAVE_LLVM=0x0$LLVM_VERSION_INT -DMESA_LLVM_VERSION_PATCH=$LLVM_VERSION_PATCH"
MESA_LLVM=1
@@ -2212,6 +2215,10 @@ else
if test "x$enable_opencl" = xyes; then
AC_MSG_ERROR([cannot enable OpenCL without LLVM])
fi
+
+ if test "x$enable_nouveau_llvm_compiler" = xyes; then
+ AC_MSG_ERROR([cannot enable Nouveau SPIR-V processing without LLVM])
+ fi
fi
dnl Directory for XVMC libs
diff --git a/src/gallium/state_trackers/clover/Makefile.am b/src/gallium/state_trackers/clover/Makefile.am
index 38b0e82e69..cb13482f4f 100644
--- a/src/gallium/state_trackers/clover/Makefile.am
+++ b/src/gallium/state_trackers/clover/Makefile.am
@@ -51,7 +51,10 @@ libclllvm_la_SOURCES = $(LLVM_SOURCES)
libspirv_la_CXXFLAGS = \
-std=c++11 \
- $(VISIBILITY_CXXFLAGS)
+ $(VISIBILITY_CXXFLAGS) \
+ $(LLVM_CXXFLAGS) \
+ $(DEFINES) \
+ -DCLANG_RESOURCE_DIR=\"$(CLANG_RESOURCE_DIR)\"
libspirv_la_SOURCES = $(SPIRV_SOURCES)
diff --git a/src/gallium/state_trackers/clover/api/program.cpp b/src/gallium/state_trackers/clover/api/program.cpp
index 2ce9d003eb..5eb0cd157e 100644
--- a/src/gallium/state_trackers/clover/api/program.cpp
+++ b/src/gallium/state_trackers/clover/api/program.cpp
@@ -103,7 +103,7 @@ clCreateProgramWithBinary(cl_context d_ctx, cl_uint n,
return { CL_INVALID_BINARY, {} };
std::string log;
- return { CL_SUCCESS, clover::spirv::compile_program(p, l, log) };
+ return { CL_SUCCESS, clover::spirv::process_program(p, l, log) };
} else {
try {
std::stringbuf bin( { (char*)p, l } );
diff --git a/src/gallium/state_trackers/clover/core/program.cpp b/src/gallium/state_trackers/clover/core/program.cpp
index 54bb07c2ec..76008f6274 100644
--- a/src/gallium/state_trackers/clover/core/program.cpp
+++ b/src/gallium/state_trackers/clover/core/program.cpp
@@ -62,15 +62,21 @@ program::compile(const ref_vector<device> &devs, const std::string &opts,
std::string log;
try {
- if (dev.ir_format() == PIPE_SHADER_IR_SPIRV) {
- log = "Compiling from source to SPIR-V is not supported yet";
- throw error(CL_INVALID_DEVICE);
+ switch (dev.ir_format()) {
+ case PIPE_SHADER_IR_TGSI:
+ _builds[&dev] = { tgsi::compile_program(_source, log), opts, log };
+ break;
+ case PIPE_SHADER_IR_LLVM:
+ case PIPE_SHADER_IR_NATIVE:
+ case PIPE_SHADER_IR_NIR:
+ _builds[&dev] = { llvm::compile_program(_source, headers,
+ dev.ir_target(), opts, log), opts, log };
+ break;
+ case PIPE_SHADER_IR_SPIRV:
+ _builds[&dev] = { clover::spirv::compile_program(_source, headers, dev.ir_format(),
+ dev.ir_target(), opts, log), opts, log };
+ break;
}
- const module m = (dev.ir_format() == PIPE_SHADER_IR_TGSI ?
- tgsi::compile_program(_source, log) :
- llvm::compile_program(_source, headers,
- dev.ir_target(), opts, log));
- _builds[&dev] = { m, opts, log };
} catch (...) {
_builds[&dev] = { module(), opts, log };
throw;
@@ -89,7 +95,7 @@ program::compile(const ref_vector<device> &devs, const std::string &opts,
throw error(CL_INVALID_BINARY);
}
- auto module = spirv::compile_program(_il, _length, log);
+ auto module = spirv::process_program(_il, _length, log);
_builds[&dev] = { module, opts, log };
} else {
log = "Only SPIR-V is supported as IL by clover for now";
@@ -115,11 +121,20 @@ program::link(const ref_vector<device> &devs, const std::string &opts,
std::string log = _builds[&dev].log;
try {
- const module m = (dev.ir_format() == PIPE_SHADER_IR_TGSI ?
- tgsi::link_program(ms) :
- llvm::link_program(ms, dev.ir_format(),
- dev.ir_target(), opts, log));
- _builds[&dev] = { m, opts, log };
+ switch (dev.ir_format()) {
+ case PIPE_SHADER_IR_TGSI:
+ _builds[&dev] = { tgsi::link_program(ms), opts, log };
+ break;
+ case PIPE_SHADER_IR_LLVM:
+ case PIPE_SHADER_IR_NATIVE:
+ case PIPE_SHADER_IR_NIR:
+ _builds[&dev] = { llvm::link_program(ms, dev.ir_format(),
+ dev.ir_target(), opts, log), opts, log };
+ break;
+ case PIPE_SHADER_IR_SPIRV:
+ _builds[&dev] = { clover::spirv::link_program(ms), opts, log };
+ break;
+ }
} catch (...) {
_builds[&dev] = { module(), opts, log };
throw;
diff --git a/src/gallium/state_trackers/clover/spirv/compiler.cpp b/src/gallium/state_trackers/clover/spirv/compiler.cpp
index 6e75e65344..9914758f12 100644
--- a/src/gallium/state_trackers/clover/spirv/compiler.cpp
+++ b/src/gallium/state_trackers/clover/spirv/compiler.cpp
@@ -24,6 +24,57 @@
#include <vector>
#include <unordered_map>
+#include <clang/Frontend/CompilerInstance.h>
+#include <clang/Frontend/TextDiagnosticBuffer.h>
+#include <clang/Frontend/TextDiagnosticPrinter.h>
+#include <clang/CodeGen/CodeGenAction.h>
+#include <clang/Basic/TargetInfo.h>
+#include <llvm/Bitcode/BitstreamWriter.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/Linker/Linker.h>
+#include <llvm/IR/DiagnosticInfo.h>
+#include <llvm/IR/DiagnosticPrinter.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+#include <llvm/Support/SourceMgr.h>
+#include <llvm/IRReader/IRReader.h>
+#include <llvm/Support/CodeGen.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/SPIRV.h>
+#include <llvm/Transforms/IPO.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <llvm/Transforms/Utils/Cloning.h>
+
+
+#include <llvm/IR/DataLayout.h>
+#if HAVE_LLVM >= 0x0307
+#include <llvm/Analysis/TargetLibraryInfo.h>
+#else
+#include <llvm/Target/TargetLibraryInfo.h>
+#endif
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Target/TargetOptions.h>
+
+#include <llvm-c/Target.h>
+#include <llvm-c/TargetMachine.h>
+#include <llvm-c/Core.h>
+
+#include "pipe/p_state.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <cstdio>
+#include <sstream>
+#include <libelf.h>
+#include <gelf.h>
+
#include <SPIRV/spirv.hpp11>
#include <spirv/spirv_parse.hpp>
@@ -192,8 +243,247 @@ namespace {
}
+namespace {
+ llvm::Module *
+ compile_spirv(llvm::LLVMContext &llvm_ctx, const std::string &source,
+ const header_map &headers,
+ const std::string &name, const std::string &triple,
+ const std::string &processor, const std::string &opts,
+ clang::LangAS::Map& address_spaces, unsigned &optimization_level,
+ std::string &r_log) {
+
+ clang::CompilerInstance c;
+ clang::EmitSPIRVAction act(&llvm_ctx);
+ std::string log;
+ llvm::raw_string_ostream s_log(log);
+
+ // Parse the compiler options:
+ std::vector<std::string> opts_array;
+ std::istringstream ss(opts);
+
+ while (!ss.eof()) {
+ std::string opt;
+ getline(ss, opt, ' ');
+ opts_array.push_back(opt);
+ }
+
+ opts_array.push_back(name);
+
+ std::vector<const char *> opts_carray;
+ opts_carray.push_back("-cc1");
+ opts_carray.push_back("-emit-spirv");
+ opts_carray.push_back("-cl-std=CL1.2");
+ opts_carray.push_back("-includeopencl-12.h");
+ for (unsigned i = 0; i < opts_array.size(); i++) {
+ opts_carray.push_back(opts_array.at(i).c_str());
+ }
+
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID;
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
+ clang::TextDiagnosticBuffer *DiagsBuffer;
+
+ DiagID = new clang::DiagnosticIDs();
+ DiagOpts = new clang::DiagnosticOptions();
+ DiagsBuffer = new clang::TextDiagnosticBuffer();
+
+ clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+ bool Success;
+
+ Success = clang::CompilerInvocation::CreateFromArgs(c.getInvocation(),
+ opts_carray.data(),
+ opts_carray.data() + opts_carray.size(),
+ Diags);
+ if (!Success) {
+ throw error(CL_INVALID_COMPILER_OPTIONS);
+ }
+
+ c.getTargetOpts().Triple = triple;
+
+ // This is a workaround otherwise clang doesn't find opencl-12.h
+ c.getHeaderSearchOpts().AddPath("/home/pmoreau/projects/nouveau/llvm_install/lib/clang/3.6.1/include",
+ clang::frontend::Angled,
+ false, false
+ );
+
+ // This is a workaround for a Clang bug which causes the number
+ // of warnings and errors to be printed to stderr.
+ // http://www.llvm.org/bugs/show_bug.cgi?id=19735
+ c.getDiagnosticOpts().ShowCarets = false;
+ c.createDiagnostics(
+ new clang::TextDiagnosticPrinter(
+ s_log,
+ &c.getDiagnosticOpts()));
+
+#if HAVE_LLVM >= 0x0306
+ c.getPreprocessorOpts().addRemappedFile(name,
+ llvm::MemoryBuffer::getMemBuffer(source).release());
+#else
+ c.getPreprocessorOpts().addRemappedFile(name,
+ llvm::MemoryBuffer::getMemBuffer(source));
+#endif
+
+ if (headers.size()) {
+ const std::string tmp_header_path = "/tmp/clover/";
+
+ c.getHeaderSearchOpts().AddPath(tmp_header_path,
+ clang::frontend::Angled,
+ false, false
+ );
+
+ for (header_map::const_iterator it = headers.begin();
+ it != headers.end(); ++it) {
+ const std::string path = tmp_header_path + std::string(it->first);
+ c.getPreprocessorOpts().addRemappedFile(path,
+#if HAVE_LLVM >= 0x0306
+ llvm::MemoryBuffer::getMemBuffer(it->second.c_str()).release());
+#else
+ llvm::MemoryBuffer::getMemBuffer(it->second.c_str()));
+#endif
+ }
+ }
+
+ optimization_level = c.getCodeGenOpts().OptimizationLevel;
+
+ // Compile the code
+ bool ExecSuccess = c.ExecuteAction(act);
+ r_log = log;
+
+ if (!ExecSuccess)
+ throw build_error();
+
+ // Get address spaces map to be able to find kernel argument address space
+ memcpy(address_spaces, c.getTarget().getAddressSpaceMap(),
+ sizeof(address_spaces));
+
+#if HAVE_LLVM >= 0x0306
+ return act.takeModule().release();
+#else
+ return act.takeModule();
+#endif
+ }
+
+ void
+ diagnostic_handler(const llvm::DiagnosticInfo &di, void *data) {
+ if (di.getSeverity() == llvm::DS_Error) {
+ std::string message = *(std::string*)data;
+ llvm::raw_string_ostream stream(message);
+ llvm::DiagnosticPrinterRawOStream dp(stream);
+ di.print(dp);
+ stream.flush();
+ *(std::string*)data = message;
+
+ throw build_error();
+ }
+ }
+
+ void
+ init_targets() {
+ static bool targets_initialized = false;
+ if (!targets_initialized) {
+ LLVMInitializeAllTargets();
+ LLVMInitializeAllTargetInfos();
+ LLVMInitializeAllTargetMCs();
+ LLVMInitializeAllAsmPrinters();
+ targets_initialized = true;
+ }
+ }
+
+ module
+ build_module_spirv(llvm::Module *mod,
+ clang::LangAS::Map& address_spaces,
+ std::string& log) {
+
+ module m;
+ struct pipe_llvm_program_header header;
+ std::string err;
+
+ llvm::SmallVector<char, 1024> spirv_bitcode;
+ llvm::raw_svector_ostream bitcode_ostream(spirv_bitcode);
+ llvm::WriteSPIRV(mod, bitcode_ostream, err);
+#if HAVE_LLVM < 0x0308
+ bitcode_ostream.flush();
+#endif
+
+ header.num_bytes = 0u;
+ std::vector<char> data;
+ data.insert(data.end(), spirv_bitcode.begin(),
+ spirv_bitcode.end());
+ m.secs.push_back(module::section(0, module::section::text,
+ header.num_bytes, data));
+
+ add_kernels_data(m, log, data);
+
+ log += err;
+
+ return m;
+ }
+
+#define DBG_SPIRV (1 << 0)
+
+ unsigned
+ get_debug_flags() {
+ static const struct debug_named_value debug_options[] = {
+ {"spirv", DBG_SPIRV, "Dump kernel SPIR-V code for targets specifying "
+ "PIPE_SHADER_IR_SPIRV"},
+ DEBUG_NAMED_VALUE_END // must be last
+ };
+ static const unsigned debug_flags =
+ debug_get_flags_option("CLOVER_DEBUG", debug_options, 0);
+
+ return debug_flags;
+ }
+
+} // End anonymous namespace
+
+module
+clover::spirv::compile_program(const std::string &source,
+ const header_map &headers,
+ enum pipe_shader_ir ir,
+ const std::string &target,
+ const std::string &opts,
+ std::string &r_log) {
+ init_targets();
+
+ size_t processor_str_len = std::string(target).find_first_of("-");
+ std::string processor(target, 0, processor_str_len);
+ std::string triple(target, processor_str_len + 1,
+ target.size() - processor_str_len - 1);
+ clang::LangAS::Map address_spaces;
+ llvm::LLVMContext llvm_ctx;
+ unsigned optimization_level;
+
+ llvm_ctx.setDiagnosticHandler(diagnostic_handler, &r_log);
+
+ // The input file name must have the .cl extension in order for the
+ // CompilerInvocation class to recognize it as an OpenCL source file.
+ llvm::Module *mod = nullptr;
+ mod = compile_spirv(llvm_ctx, source, headers, "input.cl",
+ triple, processor, opts, address_spaces,
+ optimization_level, r_log);
+
+ module m;
+ // Build the clover::module
+ r_log += std::string("PIPE_SHADER_IR_SPIRV is not really supported yet\n");
+
+ m = build_module_spirv(mod, address_spaces, r_log);
+ if (get_debug_flags() & DBG_SPIRV) {
+ unsigned int count = 0u;
+ for (auto sec : m.secs) {
+ std::ofstream file_handle = std::ofstream("/home/pmoreau/projects/nouveau/debug_spirv_clover/sec_" + std::to_string(count) + ".spv", std::ios::binary);
+ file_handle.write(sec.data.data(), sec.data.size());
+ ++count;
+ }
+ }
+#if HAVE_LLVM >= 0x0306
+ // LLVM 3.6 and newer, the user takes ownership of the module.
+ delete mod;
+#endif
+
+ return m;
+}
+
module
-clover::spirv::compile_program(const void *il, const size_t length,
+clover::spirv::process_program(const void *il, const size_t length,
std::string &r_log) {
module m;
std::vector<char> source;
@@ -228,3 +518,11 @@ clover::spirv::compile_program(const void *il, const size_t length,
return m;
}
+
+module
+clover::spirv::link_program(const std::vector<module> &modules)
+{
+ assert(modules.size() == 1);
+
+ return modules[0];
+}
diff --git a/src/gallium/state_trackers/clover/spirv/invocation.hpp b/src/gallium/state_trackers/clover/spirv/invocation.hpp
index 96470d87e6..049ad1d11d 100644
--- a/src/gallium/state_trackers/clover/spirv/invocation.hpp
+++ b/src/gallium/state_trackers/clover/spirv/invocation.hpp
@@ -24,10 +24,18 @@
#define CLOVER_SPIRV_INVOCATION_HPP
#include "core/module.hpp"
+#include "core/program.hpp"
namespace clover {
namespace spirv {
- module compile_program(const void *il,
+ module compile_program(const std::string &source,
+ const header_map &headers,
+ enum pipe_shader_ir ir,
+ const std::string &target,
+ const std::string &opts,
+ std::string &r_log);
+
+ module process_program(const void *il,
const size_t length,
std::string &r_log);

Event Timeline

pmoreau created this paste.Sep 20 2017, 1:26 AM
pmoreau created this object with visibility "Public (No Login Required)".
pmoreau created this object with edit policy "Nouveau (Project)".