Tom Stellard <thomas.stell...@amd.com> writes: > v2: > - Split build_module_native() into three separate functions. > - Code cleanups. > --- > .../state_trackers/clover/llvm/invocation.cpp | 200 > ++++++++++++++++++++- > src/gallium/targets/opencl/Makefile.am | 1 + > 2 files changed, 192 insertions(+), 9 deletions(-) > > diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp > b/src/gallium/state_trackers/clover/llvm/invocation.cpp > index 3b6b6a4..d9c3d11 100644 > --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp > +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp > @@ -45,12 +45,18 @@ > #include <llvm/Support/SourceMgr.h> > #include <llvm/IRReader/IRReader.h> > #endif > +#if HAVE_LLVM < 0x0305 > +#include <llvm/ADT/OwningPtr.h> > +#endif > #include <llvm/PassManager.h> > +#include <llvm/Support/CodeGen.h> > #include <llvm/Support/TargetSelect.h> > #include <llvm/Support/MemoryBuffer.h> > #if HAVE_LLVM < 0x0303 > #include <llvm/Support/PathV1.h> > #endif > +#include <llvm/Support/FormattedStream.h> > +#include <llvm/Support/TargetRegistry.h> > #include <llvm/Transforms/IPO.h> > #include <llvm/Transforms/IPO/PassManagerBuilder.h> > > @@ -61,6 +67,13 @@ > #else > #include <llvm/IR/DataLayout.h> > #endif > +#include <llvm/Target/TargetLibraryInfo.h> > +#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" > @@ -71,6 +84,8 @@ > #include <fstream> > #include <cstdio> > #include <sstream> > +#include <libelf.h> > +#include <gelf.h> > > using namespace clover; > > @@ -117,10 +132,11 @@ namespace { > #endif > > llvm::Module * > - compile(llvm::LLVMContext &llvm_ctx, const std::string &source, > + compile_llvm(llvm::LLVMContext &llvm_ctx, const std::string &source, > const std::string &name, const std::string &triple, > const std::string &processor, const std::string &opts, > - clang::LangAS::Map& address_spaces, compat::string &r_log) { > + clang::LangAS::Map& address_spaces, unsigned &optimization_level, > + compat::string &r_log) { > > clang::CompilerInstance c; > clang::EmitLLVMOnlyAction act(&llvm_ctx); > @@ -228,6 +244,8 @@ namespace { > // that is no executed by all threads) during its optimizaton passes. > c.getCodeGenOpts().LinkBitcodeFile = libclc_path; > > + optimization_level = c.getCodeGenOpts().OptimizationLevel; > + > // Compile the code > bool ExecSuccess = c.ExecuteAction(act); > r_log = log; > @@ -264,8 +282,8 @@ namespace { > } > > void > - internalize_functions(llvm::Module *mod, > - const std::vector<llvm::Function *> &kernels) { > + optimize(llvm::Module *mod, unsigned optimization_level, > + const std::vector<llvm::Function *> &kernels) { > > llvm::PassManager PM; > // Add a function internalizer pass. > @@ -289,7 +307,14 @@ namespace { > llvm::Function *kernel = *I; > export_list.push_back(kernel->getName().data()); > } > + PM.add(new llvm::DataLayoutPass()); > PM.add(llvm::createInternalizePass(export_list)); > + > + llvm::PassManagerBuilder PMB; > + PMB.OptLevel = optimization_level; > + PMB.LibraryInfo = new llvm::TargetLibraryInfo( > + llvm::Triple(mod->getTargetTriple())); > + PMB.populateModulePassManager(PM); > PM.run(*mod); > } > > @@ -404,6 +429,150 @@ namespace { > > return m; > } > + > + std::vector<char> > + compile_native(const llvm::Module *mod, std::string triple, > + std::string processor, compat::string &r_log) { > +
triple and processor should be const references. > + std::string log; > + LLVMTargetRef target; > + char *error_message; > + LLVMMemoryBufferRef out_buffer; > + unsigned buffer_size; > + const char *buffer_data; > + LLVMBool err; > + LLVMModuleRef mod_ref = wrap(mod); > + > + if (LLVMGetTargetFromTriple(triple.c_str(), &target, &error_message)) { > + r_log = std::string(error_message); > + LLVMDisposeMessage(error_message); > + throw build_error(); > + } > + > + LLVMTargetMachineRef tm = LLVMCreateTargetMachine( > + target, triple.c_str(), processor.c_str(), "", > + LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault); > + > + if (!tm) { > + r_log = "Could not create TargetMachine: " + triple; > + throw build_error(); > + } > + > + err = LLVMTargetMachineEmitToMemoryBuffer(tm, mod_ref, LLVMObjectFile, > + &error_message, &out_buffer); > + > + if (err) { > + LLVMDisposeTargetMachine(tm); > + r_log = std::string(error_message); > + LLVMDisposeMessage(error_message); > + throw build_error(); > + } > + > + buffer_size = LLVMGetBufferSize(out_buffer); > + buffer_data = LLVMGetBufferStart(out_buffer); > + > + std::vector<char> code(buffer_data, buffer_data + buffer_size); > + > + LLVMDisposeMemoryBuffer(out_buffer); > + LLVMDisposeTargetMachine(tm); > + > + return code; > + } > + > + std::map<std::string, unsigned> > + get_kernel_offsets(std::vector<char> &code, This argument should be a const reference. > + const std::vector<llvm::Function *> &kernels) { > + > + // One of the libelf implementations > + // (http://www.mr511.de/software/english.htm) requires calling > + // elf_version() before elf_memory(). > + // > + elf_version(EV_CURRENT); > + > + Elf *elf = elf_memory(&code[0], code.size()); > + size_t section_str_index; > + elf_getshdrstrndx(elf, §ion_str_index); > + Elf_Scn *section = NULL; > + Elf_Scn *symtab = NULL; > + GElf_Shdr symtab_header; > + > + // Find the symbol table > + while ((section = elf_nextscn(elf, section))) { > + const char *name; > + if (gelf_getshdr(section, &symtab_header) != &symtab_header) { Leak? Maybe wrap the whole thing in 'try { ... } catch(build_error &) { elf_end(elf); }'? > + throw build_error("Failed to read ELF section header\n"); > + } > + name = elf_strptr(elf, section_str_index, symtab_header.sh_name); > + if (!strcmp(name, ".symtab")) { > + symtab = section; > + break; > + } > + } > + if (!symtab) { Leak. > + throw build_error("Unable to find symbol table."); > + } > + > + // Extract symbol information from the table > + Elf_Data *symtab_data = NULL; > + GElf_Sym *symbol; > + GElf_Sym s; > + > + std::map<std::string, unsigned> kernel_offsets; > + symtab_data = elf_getdata(symtab, symtab_data); > + > + // Determine the offsets for each kernel > + for (int i = 0; (symbol = gelf_getsym(symtab_data, i, &s)); i++) { > + char *name = elf_strptr(elf, symtab_header.sh_link, > symbol->st_name); > + for (std::vector<llvm::Function*>::const_iterator it = > kernels.begin(), > + e = kernels.end(); it != e; ++it) { > + llvm::Function *f = *it; > + if (f->getName() == std::string(name)) > + kernel_offsets[f->getName()] = symbol->st_value; > + } > + } > + elf_end(elf); > + return kernel_offsets; > + } > + > + module > + build_module_native(std::vector<char> &code, This could be a const reference. > + const llvm::Module *mod, > + const std::vector<llvm::Function *> &kernels, > + clang::LangAS::Map& address_spaces, And this. > + compat::string &r_log) { > + > + std::map<std::string, unsigned> kernel_offsets = > + get_kernel_offsets(code, kernels); > + > + // Begin building the clover module > + module m; > + struct pipe_llvm_program_header header; > + > + // Store the generated ELF binary in the module's text section. > + header.num_bytes = code.size(); > + std::string data; > + data.insert(0, (char*)(&header), sizeof(header)); This could be an append call as well. > + data.append(code.begin(), code.end()); > + m.secs.push_back(module::section(0, module::section::text, > + header.num_bytes, data)); > + > + for (std::map<std::string, unsigned>::iterator i = > kernel_offsets.begin(), > + e = kernel_offsets.end(); i != e; ++i) { > + compat::vector<module::argument> args = > + get_kernel_args(mod, i->first, address_spaces); > + m.syms.push_back(module::symbol(i->first, 0, i->second, args )); > + } > + > + return m; > + } > + > + void > + init_targets() { > + LLVMInitializeAllTargets(); > + LLVMInitializeAllTargetInfos(); > + LLVMInitializeAllTargetMCs(); > + LLVMInitializeAllAsmPrinters(); > + } > } // End anonymous namespace > > module > @@ -413,23 +582,31 @@ clover::compile_program_llvm(const compat::string > &source, > const compat::string &opts, > compat::string &r_log) { > > + static bool targets_initialized = false; > + > + if (!targets_initialized) { > + init_targets(); > + targets_initialized = true; > + } > + Meh... There's no reason why you couldn't move the whole thing to init_targets(), including the conditional and static variable. > std::vector<llvm::Function *> kernels; > 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); > clang::LangAS::Map address_spaces; > - > llvm::LLVMContext llvm_ctx; > + unsigned optimization_level; > > // 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 = compile(llvm_ctx, source, "input.cl", triple, > processor, > - opts, address_spaces, r_log); > + llvm::Module *mod = compile_llvm(llvm_ctx, source, "input.cl", triple, > + processor, opts, address_spaces, > + optimization_level, r_log); > > find_kernels(mod, kernels); > > - internalize_functions(mod, kernels); > + optimize(mod, optimization_level, kernels); > > module m; > // Build the clover::module > @@ -439,9 +616,14 @@ clover::compile_program_llvm(const compat::string > &source, > assert(0); > m = module(); > break; > - default: > + case PIPE_SHADER_IR_LLVM: > m = build_module_llvm(mod, kernels, address_spaces); > break; > + case PIPE_SHADER_IR_NATIVE: { > + std::vector<char> code = compile_native(mod, triple, processor, > r_log); > + m = build_module_native(code, mod, kernels, address_spaces, r_log); > + break; > + } > } > #if HAVE_LLVM >= 0x0306 > // LLVM 3.6 and newer, the user takes ownership of the module. > diff --git a/src/gallium/targets/opencl/Makefile.am > b/src/gallium/targets/opencl/Makefile.am > index 43ba5dd..1c5a908 100644 > --- a/src/gallium/targets/opencl/Makefile.am > +++ b/src/gallium/targets/opencl/Makefile.am > @@ -23,6 +23,7 @@ lib@OPENCL_LIBNAME@_la_LIBADD = \ > $(top_builddir)/src/util/libmesautil.la \ > $(GALLIUM_PIPE_LOADER_WINSYS_LIBS) \ > $(GALLIUM_PIPE_LOADER_CLIENT_LIBS) \ > + $(ELF_LIB) \ > -ldl \ > -lclangCodeGen \ > -lclangFrontendTool \ > -- > 1.8.5.5
pgp6T2WMv0kYG.pgp
Description: PGP signature
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev