diff options
author | Tom Stellard <thomas.stellard@amd.com> | 2012-04-24 12:44:53 -0400 |
---|---|---|
committer | Tom Stellard <thomas.stellard@amd.com> | 2012-04-24 13:48:39 -0400 |
commit | d6e6d7ae8331a081bf0bb648d277b950a3777766 (patch) | |
tree | 23c78ed01122bd65dbae36a69d6631e5d1087d1e | |
parent | 8806850f01c0498fe2de2522ad2c797595a6b408 (diff) |
clover: Add function for building a clover::module for non-TGSI targets
-rw-r--r-- | src/gallium/state_trackers/clover/llvm/invocation.cpp | 158 |
1 files changed, 149 insertions, 9 deletions
diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp index 89e21bf9289..e75e7dc960f 100644 --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp @@ -22,24 +22,33 @@ #include "core/compiler.hpp" -#if 0 #include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/TextDiagnosticPrinter.h> #include <clang/CodeGen/CodeGenAction.h> +#include <llvm/Bitcode/BitstreamWriter.h> +#include <llvm/Bitcode/ReaderWriter.h> +#include <llvm/DerivedTypes.h> +#include <llvm/Linker.h> #include <llvm/LLVMContext.h> +#include <llvm/Module.h> +#include <llvm/PassManager.h> #include <llvm/Support/TargetSelect.h> #include <llvm/Support/MemoryBuffer.h> +#include <llvm/Support/PathV1.h> +#include <llvm/Target/TargetData.h> +#include <llvm/Transforms/IPO/PassManagerBuilder.h> + +#include "util/u_memory.h" #include <iostream> #include <iomanip> #include <fstream> #include <cstdio> -#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 +87,148 @@ namespace { compat::istream cs(str); return module::deserialize(cs); } -} #endif + module + build_module_llvm(const std::string &source, const std::string &target, + const std::string &name) { + + /* Compile the kernel */ + clang::CompilerInstance c; + module m; + clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext()); + std::string log; + std::string libclc_target = ""; + llvm::raw_string_ostream s_log(log); + +#if HAVE_LLVM <= 0x0300 + c.getFrontendOpts().Inputs.push_back( + std::make_pair(clang::IK_OpenCL, "cl_input")); +#else + c.getFrontendOpts().Inputs.push_back( + clang::FrontendInputFile("cl_input", clang::IK_OpenCL)); +#endif + c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; + c.getHeaderSearchOpts().UseBuiltinIncludes = false; +#if HAVE_LLVM < 0x0300 + c.getHeaderSearchOpts().UseStandardIncludes = false; +#else + c.getHeaderSearchOpts().UseStandardSystemIncludes = false; +#endif + c.getLangOpts().NoBuiltin = true; + c.getTargetOpts().Triple = target; + libclc_target = target + "--"; + c.getInvocation().setLangDefaults(clang::IK_OpenCL); + c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter( + s_log, c.getDiagnosticOpts())); + + c.getPreprocessorOpts().addRemappedFile( + "cl_input", llvm::MemoryBuffer::getMemBuffer(source)); + + if (!c.ExecuteAction(act)) + throw build_error(log); + + c.getLangOpts().SinglePrecisionConstants = true; + + /* Link the kernel with libclc */ + llvm::PassManager PM; + llvm::PassManagerBuilder Builder; + bool isNative; + llvm::Module * mod = act.takeModule(); + llvm::Linker linker("clover", mod); + + /* XXX: We need to find a better way to find this library. */ + linker.LinkInFile(llvm::sys::Path(LIBCLC_PATH + libclc_target + "/lib/builtins.bc"), isNative); + mod = linker.releaseModule(); + Builder.populateLTOPassManager(PM, false, true); + Builder.OptLevel = 2; + PM.run(*mod); + + /* Build the clover::module */ + unsigned char * prog; + uint32_t prog_sz; + +#if HAVE_LLVM > 0x0300 + llvm::SmallVector<char, 1024> llvm_bitcode; + llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode); +#else + std::vector<unsigned char> llvm_bitcode; +#endif + llvm::BitstreamWriter writer(llvm_bitcode); + +#if HAVE_LLVM <= 0x0300 + llvm::WriteBitcodeToStream(mod, writer); +#else + llvm::WriteBitcodeToFile(mod, bitcode_ostream); + bitcode_ostream.flush(); +#endif + + prog_sz = llvm_bitcode.size() * sizeof(unsigned char); + + /* We need to add 4 to the program size, because we will + * be preprending the length of the program to the bitcode string. */ + prog = (unsigned char *)MALLOC(prog_sz + 4); + ((uint32_t *)prog)[0] = prog_sz; + memcpy(prog + 4, &llvm_bitcode[0], prog_sz); + + std::string kernel_name; + compat::vector<module::argument> args; + const llvm::NamedMDNode * kernel_node = + mod->getNamedMetadata("opencl.kernels"); + /* XXX: Support more than one kernel */ + /* XXX: Error if there are no kernels */ + assert(kernel_node->getNumOperands() == 1); + + llvm::Function * kernel_func = llvm::dyn_cast<llvm::Function>( + 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<llvm::PointerType>(arg_type) and arg.hasByValAttr()) { + arg_type = + llvm::dyn_cast<llvm::PointerType>(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<llvm::PointerType>(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)); + } + } + m.syms.push_back(module::symbol(kernel_name, 0, 0, args )); + m.secs.push_back(module::section(0, module::section::text, prog_sz, + compat::vector<char>((char *)prog, prog_sz ))); + return m; + } +} module clover::compile_program_llvm(const compat::string &source, const compat::string &target) { + + if (target == compat::string("TGSI")) { #if 0 - build_binary(source, target, "cl_input"); - module m = load_binary("cl_input.o"); - std::remove("cl_input.o"); - return m; + build_binary(source, target, "cl_input"); + module m = load_binary("cl_input.o"); + std::remove("cl_input.o"); + return m; +#else + return module(); + } else { + return build_module_llvm(source, target, "cl_input"); + } #endif - return module(); } |