From 2043c5f37cf1f1b64a8f5d9ae04bbf8e7860f616 Mon Sep 17 00:00:00 2001 From: Pierre Moreau <pierre.morrow@free.fr> Date: Sat, 10 Feb 2018 21:44:45 +0100 Subject: clover/llvm: Add functions for compiling from source to SPIR-V Reviewed-by: Karol Herbst <kherbst@redhat.com> Reviewed-by: Francisco Jerez <currojerez@riseup.net> --- .../state_trackers/clover/llvm/invocation.cpp | 99 ++++++++++++++++++---- .../state_trackers/clover/llvm/invocation.hpp | 8 ++ src/gallium/state_trackers/clover/meson.build | 2 +- 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp index deaf1cc4b43..d71ddf8b01b 100644 --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp @@ -30,6 +30,9 @@ #include <llvm/Support/raw_ostream.h> #include <llvm/Transforms/IPO/PassManagerBuilder.h> #include <llvm-c/Target.h> +#ifdef HAVE_CLOVER_SPIRV +#include <LLVMSPIRVLib/LLVMSPIRVLib.h> +#endif #include <clang/CodeGen/CodeGenAction.h> #include <clang/Lex/PreprocessorOptions.h> @@ -51,6 +54,9 @@ #include "llvm/invocation.hpp" #include "llvm/metadata.hpp" #include "llvm/util.hpp" +#ifdef HAVE_CLOVER_SPIRV +#include "spirv/invocation.hpp" +#endif #include "util/algorithm.hpp" @@ -182,7 +188,7 @@ namespace { } std::unique_ptr<clang::CompilerInstance> - create_compiler_instance(const device &dev, + create_compiler_instance(const device &dev, const std::string& ir_target, const std::vector<std::string> &opts, std::string &r_log) { std::unique_ptr<clang::CompilerInstance> c { new clang::CompilerInstance }; @@ -196,7 +202,7 @@ namespace { const std::vector<const char *> copts = map(std::mem_fn(&std::string::c_str), opts); - const target &target = dev.ir_target(); + const target &target = ir_target; const std::string &device_clc_version = dev.device_clc_version(); if (!compat::create_compiler_invocation_from_args( @@ -235,19 +241,29 @@ namespace { compile(LLVMContext &ctx, clang::CompilerInstance &c, const std::string &name, const std::string &source, const header_map &headers, const device &dev, - const std::string &opts, std::string &r_log) { + const std::string &opts, bool use_libclc, std::string &r_log) { 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_INCLUDEDIR, - clang::frontend::Angled, - false, false); + if (use_libclc) { + // Add libclc generic search path + c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR, + clang::frontend::Angled, + false, false); + + // Add libclc include + c.getPreprocessorOpts().Includes.push_back("clc/clc.h"); + } else { + // Add opencl-c generic search path + c.getHeaderSearchOpts().AddPath(CLANG_RESOURCE_DIR, + clang::frontend::Angled, + false, false); - // Add libclc include - c.getPreprocessorOpts().Includes.push_back("clc/clc.h"); + // Add opencl include + c.getPreprocessorOpts().Includes.push_back("opencl-c.h"); + } // Add definition for the OpenCL version c.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=" + @@ -279,8 +295,9 @@ namespace { // attribute will prevent Clang from creating illegal uses of // barrier() (e.g. Moving barrier() inside a conditional that is // no executed by all threads) during its optimizaton passes. - compat::add_link_bitcode_file(c.getCodeGenOpts(), - LIBCLC_LIBEXECDIR + dev.ir_target() + ".bc"); + if (use_libclc) + compat::add_link_bitcode_file(c.getCodeGenOpts(), + LIBCLC_LIBEXECDIR + dev.ir_target() + ".bc"); // Compile the code clang::EmitLLVMOnlyAction act(&ctx); @@ -301,8 +318,10 @@ clover::llvm::compile_program(const std::string &source, debug::log(".cl", "// Options: " + opts + '\n' + source); auto ctx = create_context(r_log); - auto c = create_compiler_instance(dev, tokenize(opts + " input.cl"), r_log); - auto mod = compile(*ctx, *c, "input.cl", source, headers, dev, opts, r_log); + auto c = create_compiler_instance(dev, dev.ir_target(), + tokenize(opts + " input.cl"), r_log); + auto mod = compile(*ctx, *c, "input.cl", source, headers, dev, opts, true, + r_log); if (has_flag(debug::llvm)) debug::log(".ll", print_module_bitcode(*mod)); @@ -363,14 +382,14 @@ namespace { module clover::llvm::link_program(const std::vector<module> &modules, - const device &dev, - const std::string &opts, std::string &r_log) { + const device &dev, const std::string &opts, + std::string &r_log) { std::vector<std::string> options = tokenize(opts + " input.cl"); const bool create_library = count("-create-library", options); erase_if(equals("-create-library"), options); auto ctx = create_context(r_log); - auto c = create_compiler_instance(dev, options, r_log); + auto c = create_compiler_instance(dev, dev.ir_target(), options, r_log); auto mod = link(*ctx, *c, modules, r_log); optimize(*mod, c->getCodeGenOpts().OptimizationLevel, !create_library); @@ -395,3 +414,51 @@ clover::llvm::link_program(const std::vector<module> &modules, unreachable("Unsupported IR."); } } + +#ifdef HAVE_CLOVER_SPIRV +module +clover::llvm::compile_to_spirv(const std::string &source, + const header_map &headers, + const device &dev, + const std::string &opts, + std::string &r_log) { + if (has_flag(debug::clc)) + debug::log(".cl", "// Options: " + opts + '\n' + source); + + auto ctx = create_context(r_log); + const std::string target = dev.address_bits() == 32u ? + "-spir-unknown-unknown" : + "-spir64-unknown-unknown"; + auto c = create_compiler_instance(dev, target, + tokenize(opts + " input.cl"), r_log); + auto mod = compile(*ctx, *c, "input.cl", source, headers, dev, opts, false, + r_log); + + if (has_flag(debug::llvm)) + debug::log(".ll", print_module_bitcode(*mod)); + + std::string error_msg; + if (!::llvm::regularizeLlvmForSpirv(mod.get(), error_msg)) { + r_log += "Failed to regularize LLVM IR for SPIR-V: " + error_msg + ".\n"; + throw error(CL_INVALID_VALUE); + } + + std::ostringstream os; + if (!::llvm::writeSpirv(mod.get(), os, error_msg)) { + r_log += "Translation from LLVM IR to SPIR-V failed: " + error_msg + ".\n"; + throw error(CL_INVALID_VALUE); + } + + const std::string osContent = os.str(); + std::vector<char> binary(osContent.begin(), osContent.end()); + if (binary.empty()) { + r_log += "Failed to retrieve SPIR-V binary.\n"; + throw error(CL_INVALID_VALUE); + } + + if (has_flag(debug::spirv)) + debug::log(".spvasm", spirv::print_module(binary, dev.device_version())); + + return spirv::compile_program(binary, dev, r_log); +} +#endif diff --git a/src/gallium/state_trackers/clover/llvm/invocation.hpp b/src/gallium/state_trackers/clover/llvm/invocation.hpp index ff9caa457ca..1f0e9db2cf7 100644 --- a/src/gallium/state_trackers/clover/llvm/invocation.hpp +++ b/src/gallium/state_trackers/clover/llvm/invocation.hpp @@ -40,6 +40,14 @@ namespace clover { const device &device, const std::string &opts, std::string &r_log); + +#ifdef HAVE_CLOVER_SPIRV + module compile_to_spirv(const std::string &source, + const header_map &headers, + const device &dev, + const std::string &opts, + std::string &r_log); +#endif } } diff --git a/src/gallium/state_trackers/clover/meson.build b/src/gallium/state_trackers/clover/meson.build index 0d8e0675eb9..2f5b287d976 100644 --- a/src/gallium/state_trackers/clover/meson.build +++ b/src/gallium/state_trackers/clover/meson.build @@ -53,7 +53,7 @@ libclllvm = static_library( dep_llvm.version(), 'include', )), ], - dependencies : [dep_llvm, dep_elf], + dependencies : [dep_llvm, dep_elf, dep_llvmspirvlib], override_options : clover_cpp_std, ) -- cgit v1.2.3