[Mesa-dev] [PATCH 12/13] clover: Add function for building a clover::module for non-TGSI targets v4
Francisco Jerez
currojerez at riseup.net
Sun May 27 05:33:15 PDT 2012
tstellar at gmail.com writes:
> From: Tom Stellard <thomas.stellard at amd.com>
>
> 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
> ---
> .../state_trackers/clover/core/compiler.hpp | 2 +
> src/gallium/state_trackers/clover/core/program.cpp | 9 +-
> .../state_trackers/clover/llvm/invocation.cpp | 167 ++++++++++++++++++--
> 3 files changed, 164 insertions(+), 14 deletions(-)
>
> diff --git a/src/gallium/state_trackers/clover/core/compiler.hpp b/src/gallium/state_trackers/clover/core/compiler.hpp
> index 686c7d8..a43050a 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 06ac2af..8e34696 100644
> --- a/src/gallium/state_trackers/clover/core/program.cpp
> +++ b/src/gallium/state_trackers/clover/core/program.cpp
> @@ -47,9 +47,14 @@ _cl_program::build(const std::vector<clover::device *> &devs) {
>
> for (auto dev : devs) {
> try {
> - auto module = (dev->ir_target() == "tgsi" ?
> + // XXX: We need to check the input source to determine which
> + // compile_program() call to use. If the input is TGSI we
> + // should use compile_program_tgsi, otherwise we should use
> + // compile_program_llvm
> + 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 89e21bf..92f132b 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 <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 "pipe/p_state.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 +88,150 @@ 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_compute_program * program;
> +
> + llvm::SmallVector<char, 1024> llvm_bitcode;
> + llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode);
> + llvm::BitstreamWriter writer(llvm_bitcode);
> + llvm::WriteBitcodeToFile(mod, bitcode_ostream);
> + bitcode_ostream.flush();
> +
> + program = (struct pipe_compute_program *)
> + MALLOC(sizeof(struct pipe_compute_program));
> +
> + program->num_bytes = llvm_bitcode.size() * sizeof(unsigned char);
> + program->prog = (unsigned char *)MALLOC(program->num_bytes);
> + memcpy(program->prog, &llvm_bitcode[0], program->num_bytes);
> +
Who is going to take ownership of this memory? The contents of
clover::module::section are supposed to be a self-contained data
structure in a form that can be passed around, serialized and
deserialized (using clCreateProgramWithBinary). That's not going to
work if you stick pointers into it.
It should be as simple as:
| header.num_bytes = llvm_bitcode.size();
| sec.data.insert(sec.data.end(), (char *)header,
| (char *)header + sizeof(header));
| sec.data.insert(sec.data.end(), llvm_bitcode.begin(),
| llvm_bitcode.end());
> + std::string kernel_name;
> + compat::vector<module::argument> 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<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) && 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,
> + sizeof(struct pipe_compute_program),
> + compat::vector<char>((char *)program,
> + sizeof(struct pipe_compute_program))));
> + 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);
> + }
> }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 229 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20120527/a47d5028/attachment-0001.pgp>
More information about the mesa-dev
mailing list