summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2016-02-18 15:05:06 +0100
committerHans de Goede <hdegoede@redhat.com>2016-07-02 12:21:28 +0200
commit144a967757d2c8ddf5b45a52f37ecfb7758c42fd (patch)
tree769aef0b5562d70f547662bebde002fa4d268afd
parentd7dfd4cb511b3190c74f5a03ca9bd8351ad6d062 (diff)
Clover: Add support for the llvm TGSI backend
This commit adds support for running OpenCL kernels on gallium drivers which have PIPE_SHADER_IR_TGSI. Note that the old hack to run kernels written in TGSI via Clover is left in place for testing purposes, this now requires that the program starts with "main 0 " and contains "COMP\n". Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--src/gallium/drivers/nouveau/nvc0/nvc0_screen.c6
-rw-r--r--src/gallium/state_trackers/clover/core/program.cpp3
-rw-r--r--src/gallium/state_trackers/clover/llvm/invocation.cpp104
3 files changed, 110 insertions, 3 deletions
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c
index e0bfd3b414..2b406d985b 100644
--- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c
+++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c
@@ -472,6 +472,12 @@ nvc0_screen_get_compute_param(struct pipe_screen *pscreen,
RET((uint32_t []) { screen->mp_count_compute });
case PIPE_COMPUTE_CAP_MAX_CLOCK_FREQUENCY:
RET((uint32_t []) { 512 }); /* FIXME: arbitrary limit */
+ case PIPE_COMPUTE_CAP_IR_TARGET: {
+ const char *tripple = "-tgsi--";
+ if (data)
+ sprintf(data, "%s", tripple);
+ return strlen(tripple) + 1;
+ }
default:
return 0;
}
diff --git a/src/gallium/state_trackers/clover/core/program.cpp b/src/gallium/state_trackers/clover/core/program.cpp
index 6eebd9c5cd..555ae8ba60 100644
--- a/src/gallium/state_trackers/clover/core/program.cpp
+++ b/src/gallium/state_trackers/clover/core/program.cpp
@@ -55,7 +55,8 @@ program::build(const ref_vector<device> &devs, const char *opts,
std::string log;
try {
- auto module = (dev.ir_format() == PIPE_SHADER_IR_TGSI ?
+ auto module = ((_source.compare(0, 7, "main 0 ") == 0 &&
+ _source.find("COMP\n") != std::string::npos) ?
compile_program_tgsi(_source, log) :
compile_program_llvm(_source, headers,
dev.ir_format(),
diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp
index 44c7e1eb2c..a975da73f8 100644
--- a/src/gallium/state_trackers/clover/llvm/invocation.cpp
+++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp
@@ -34,6 +34,7 @@
#include <llvm/Bitcode/BitstreamWriter.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Linker/Linker.h>
+#include <llvm/IR/Constants.h>
#include <llvm/IR/DiagnosticInfo.h>
#include <llvm/IR/DiagnosticPrinter.h>
#include <llvm/IR/DerivedTypes.h>
@@ -70,6 +71,8 @@
#include <llvm-c/Core.h>
#include "pipe/p_state.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_text.h"
#include "util/u_memory.h"
#include "util/u_math.h"
@@ -405,6 +408,19 @@ namespace {
return res;
}
+ unsigned
+ get_kernel_metadata_int(const llvm::Function *kernel_func,
+ llvm::StringRef name) {
+ const llvm::MDNode *md_node;
+
+ md_node = kernel_func->getMetadata(name);
+ assert(md_node);
+
+ llvm::ConstantInt *val = llvm::mdconst::dyn_extract<llvm::ConstantInt>(
+ md_node->getOperand(0));
+ return val->getZExtValue();
+ }
+
#elif HAVE_LLVM >= 0x0306
const llvm::MDNode *
@@ -737,6 +753,50 @@ namespace {
return code;
}
+ std::string
+ compile_tgsi(const llvm::Module *mod, const std::string &triple,
+ const std::string &processor, unsigned dump_tgsi,
+ std::string &r_log) {
+
+ std::string log;
+ LLVMTargetRef target;
+ char *error_message;
+ LLVMMemoryBufferRef out_buffer;
+ unsigned buffer_size;
+ const char *buffer_data;
+ LLVMModuleRef mod_ref = wrap(mod);
+
+ if (LLVMGetTargetFromTriple(triple.c_str(), &target, &error_message)) {
+ r_log = std::string(error_message);
+ LLVMDisposeMessage(error_message);
+ throw compile_error();
+ }
+
+ LLVMTargetMachineRef tm = LLVMCreateTargetMachine(
+ target, triple.c_str(), processor.c_str(), "",
+ LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault);
+
+ if (!tm) {
+ r_log = "Could not create TargetMachine: " + triple;
+ throw compile_error();
+ }
+
+ emit_code(tm, mod_ref, LLVMAssemblyFile, &out_buffer, r_log);
+
+ buffer_size = LLVMGetBufferSize(out_buffer);
+ buffer_data = LLVMGetBufferStart(out_buffer);
+
+ std::string tgsi_source = std::string(buffer_data, buffer_size);
+
+ LLVMDisposeMemoryBuffer(out_buffer);
+ LLVMDisposeTargetMachine(tm);
+
+ if (dump_tgsi)
+ debug_log(tgsi_source, ".tgsi");
+
+ return tgsi_source;
+ }
+
std::map<std::string, unsigned>
get_kernel_offsets(std::vector<char> &code,
const std::vector<llvm::Function *> &kernels,
@@ -835,6 +895,37 @@ namespace {
return m;
}
+ module
+ build_module_tgsi(std::string &tgsi_source,
+ llvm::Module *mod,
+ const clang::LangAS::Map &address_spaces,
+ std::string &r_log) {
+ module m;
+
+ const std::vector<llvm::Function *> kernels = find_kernels(mod);
+ for (unsigned i = 0; i < kernels.size(); ++i) {
+ std::string kernel_name = kernels[i]->getName();
+ unsigned offset =
+ get_kernel_metadata_int(kernels[i], "tgsi_kernel_start");
+ std::vector<module::argument> args =
+ get_kernel_args(mod, kernel_name, address_spaces);
+ m.syms.push_back(module::symbol(kernel_name, 0, offset, args ));
+ }
+
+ tgsi_token prog[1024];
+
+ if (!tgsi_text_translate(tgsi_source.c_str(), prog, ARRAY_SIZE(prog))) {
+ r_log = "translate failed";
+ throw compile_error();
+ }
+
+ unsigned sz = tgsi_num_tokens(prog) * sizeof(tgsi_token);
+ std::vector<char> data( (char *)prog, (char *)prog + sz );
+ m.secs.push_back({ 0, module::section::text, sz, data });
+
+ return m;
+ }
+
void
diagnostic_handler(const llvm::DiagnosticInfo &di, void *data) {
if (di.getSeverity() == llvm::DS_Error) {
@@ -864,6 +955,7 @@ namespace {
#define DBG_CLC (1 << 0)
#define DBG_LLVM (1 << 1)
#define DBG_ASM (1 << 2)
+#define DBG_TGSI (1 << 3)
unsigned
get_debug_flags() {
@@ -872,6 +964,8 @@ namespace {
{"llvm", DBG_LLVM, "Dump the generated LLVM IR for all kernels."},
{"asm", DBG_ASM, "Dump kernel assembly code for targets specifying "
"PIPE_SHADER_IR_NATIVE"},
+ {"tgsi", DBG_TGSI, "Dump kernel tgsi code for targets specifying "
+ "PIPE_SHADER_IR_TGSI"},
DEBUG_NAMED_VALUE_END // must be last
};
static const unsigned debug_flags =
@@ -925,11 +1019,17 @@ clover::compile_program_llvm(const std::string &source,
// Build the clover::module
switch (ir) {
case PIPE_SHADER_IR_NIR:
- case PIPE_SHADER_IR_TGSI:
- //XXX: Handle TGSI, NIR
+ //XXX: Handle NIR
assert(0);
m = module();
break;
+ case PIPE_SHADER_IR_TGSI: {
+ std::string tgsi_source = compile_tgsi(mod, triple, processor,
+ get_debug_flags() & DBG_TGSI,
+ r_log);
+ m = build_module_tgsi(tgsi_source, mod, address_spaces, r_log);
+ break;
+ }
case PIPE_SHADER_IR_LLVM:
m = build_module_llvm(mod, address_spaces);
break;