From: Tom Stellard Date: Tue, 24 Apr 2012 16:44:53 +0000 (-0400) Subject: clover: Add function for building a clover::module for non-TGSI targets v6 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=46a13b3b11d859e131399853c11ae2be0eb02f0a;p=mesa.git clover: Add function for building a clover::module for non-TGSI targets v6 v2: -Separate IR type and LLVM triple -Do the OpenCL C->LLVM IR and linking steps for all PIPE_SHADER_IR types. v3: - Coding style fixes - Removed compatibility code for LLVM < 3.1 - Split build_module_llvm() into three functions: compile(), link(), and build_module_llvm() v4: - Use struct pipe_compute_program v5: - Don't malloc memory for struct pipe_llvm_program v6: - Fix serialization of llvm bytecode Reviewed-by: Francisco Jerez --- diff --git a/src/gallium/state_trackers/clover/core/compiler.hpp b/src/gallium/state_trackers/clover/core/compiler.hpp index 686c7d83f83..a43050a22a3 100644 --- a/src/gallium/state_trackers/clover/core/compiler.hpp +++ b/src/gallium/state_trackers/clover/core/compiler.hpp @@ -25,6 +25,7 @@ #include "core/compat.hpp" #include "core/module.hpp" +#include "pipe/p_defines.h" namespace clover { class build_error { @@ -44,6 +45,7 @@ namespace clover { }; module compile_program_llvm(const compat::string &source, + enum pipe_shader_ir ir, const compat::string &target); module compile_program_tgsi(const compat::string &source); diff --git a/src/gallium/state_trackers/clover/core/program.cpp b/src/gallium/state_trackers/clover/core/program.cpp index 06ac2aff2ff..6ca8080c925 100644 --- a/src/gallium/state_trackers/clover/core/program.cpp +++ b/src/gallium/state_trackers/clover/core/program.cpp @@ -47,9 +47,10 @@ _cl_program::build(const std::vector &devs) { for (auto dev : devs) { try { - auto module = (dev->ir_target() == "tgsi" ? + auto module = (dev->ir_format() == PIPE_SHADER_IR_TGSI ? compile_program_tgsi(__source) : - compile_program_llvm(__source, dev->ir_target())); + compile_program_llvm(__source, dev->ir_format(), + dev->ir_target())); __binaries.insert({ dev, module }); } catch (build_error &e) { diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp index 89e21bf9289..27276bc6a19 100644 --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp @@ -22,24 +22,34 @@ #include "core/compiler.hpp" -#if 0 #include #include #include +#include +#include +#include +#include #include +#include +#include #include #include +#include +#include +#include + +#include "pipe/p_state.h" +#include "util/u_memory.h" #include #include #include #include -#endif using namespace clover; -#if 0 namespace { +#if 0 void build_binary(const std::string &source, const std::string &target, const std::string &name) { @@ -78,17 +88,148 @@ namespace { compat::istream cs(str); return module::deserialize(cs); } -} #endif + llvm::Module * + compile(const std::string &source, const std::string &name, + const std::string &triple) { + + clang::CompilerInstance c; + clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext()); + std::string log; + llvm::raw_string_ostream s_log(log); + + c.getFrontendOpts().Inputs.push_back( + clang::FrontendInputFile(name, clang::IK_OpenCL)); + c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; + c.getHeaderSearchOpts().UseBuiltinIncludes = true; + c.getHeaderSearchOpts().UseStandardSystemIncludes = true; + c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR; + + // Add libclc generic search path + c.getHeaderSearchOpts().AddPath(LIBCLC_PATH "/generic/include/", + clang::frontend::Angled, + false, false, false); + + // Add libclc include + c.getPreprocessorOpts().Includes.push_back("clc/clc.h"); + + // clc.h requires that this macro be defined: + c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers"); + + c.getLangOpts().NoBuiltin = true; + c.getTargetOpts().Triple = triple; + c.getInvocation().setLangDefaults(clang::IK_OpenCL); + c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter( + s_log, c.getDiagnosticOpts())); + + c.getPreprocessorOpts().addRemappedFile(name, + llvm::MemoryBuffer::getMemBuffer(source)); + + // Compile the code + if (!c.ExecuteAction(act)) + throw build_error(log); + + return act.takeModule(); + } + + void + link(llvm::Module *mod, const std::string &triple) { + + llvm::PassManager PM; + llvm::PassManagerBuilder Builder; + bool isNative; + llvm::Linker linker("clover", mod); + + // Link the kernel with libclc + linker.LinkInFile(llvm::sys::Path(LIBCLC_PATH + triple + "/lib/builtins.bc"), isNative); + mod = linker.releaseModule(); + + // Run link time optimizations + Builder.populateLTOPassManager(PM, false, true); + Builder.OptLevel = 2; + PM.run(*mod); + } + + module + build_module_llvm(llvm::Module *mod) { + + module m; + struct pipe_llvm_program_header header; + + llvm::SmallVector llvm_bitcode; + llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode); + llvm::BitstreamWriter writer(llvm_bitcode); + llvm::WriteBitcodeToFile(mod, bitcode_ostream); + bitcode_ostream.flush(); + + std::string kernel_name; + compat::vector args; + const llvm::NamedMDNode *kernel_node = + mod->getNamedMetadata("opencl.kernels"); + // XXX: Support more than one kernel + assert(kernel_node->getNumOperands() <= 1); + + llvm::Function *kernel_func = llvm::dyn_cast( + kernel_node->getOperand(0)->getOperand(0)); + kernel_name = kernel_func->getName(); + + for (llvm::Function::arg_iterator I = kernel_func->arg_begin(), + E = kernel_func->arg_end(); I != E; ++I) { + llvm::Argument &arg = *I; + llvm::Type *arg_type = arg.getType(); + llvm::TargetData TD(kernel_func->getParent()); + unsigned arg_size = TD.getTypeStoreSize(arg_type); + + if (llvm::isa(arg_type) && arg.hasByValAttr()) { + arg_type = + llvm::dyn_cast(arg_type)->getElementType(); + } + + if (arg_type->isPointerTy()) { + // XXX: Figure out LLVM->OpenCL address space mappings for each + // target. I think we need to ask clang what these are. For now, + // pretend everything is in the global address space. + unsigned address_space = llvm::cast(arg_type)->getAddressSpace(); + switch (address_space) { + default: + args.push_back(module::argument(module::argument::global, arg_size)); + break; + } + } else { + args.push_back(module::argument(module::argument::scalar, arg_size)); + } + } + + header.num_bytes = llvm_bitcode.size(); + std::string data; + data.insert(0, (char*)(&header), sizeof(header)); + data.insert(data.end(), llvm_bitcode.begin(), + llvm_bitcode.end()); + m.syms.push_back(module::symbol(kernel_name, 0, 0, args )); + m.secs.push_back(module::section(0, module::section::text, + header.num_bytes, data)); + + return m; + } +} // End anonymous namespace + module clover::compile_program_llvm(const compat::string &source, - const compat::string &target) { -#if 0 - build_binary(source, target, "cl_input"); - module m = load_binary("cl_input.o"); - std::remove("cl_input.o"); - return m; -#endif - return module(); + enum pipe_shader_ir ir, + const compat::string &triple) { + + llvm::Module *mod = compile(source, "cl_input", triple); + + link(mod, triple); + + // Build the clover::module + switch (ir) { + case PIPE_SHADER_IR_TGSI: + //XXX: Handle TGSI + assert(0); + return module(); + default: + return build_module_llvm(mod); + } }