1c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// 2a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2012-2016 Francisco Jerez 3a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2012-2016 Advanced Micro Devices, Inc. 4a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2014-2016 Jan Vesely 5a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2014-2015 Serge Martin 6a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2015 Zoltan Gilian 7c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// 8c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// Permission is hereby granted, free of charge, to any person obtaining a 9c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// copy of this software and associated documentation files (the "Software"), 10c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// to deal in the Software without restriction, including without limitation 11c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// the rights to use, copy, modify, merge, publish, distribute, sublicense, 12c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// and/or sell copies of the Software, and to permit persons to whom the 13c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// Software is furnished to do so, subject to the following conditions: 14c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// 15c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// The above copyright notice and this permission notice shall be included in 16c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// all copies or substantial portions of the Software. 17c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// 18c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// OTHER DEALINGS IN THE SOFTWARE. 25c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// 26c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez 2776136c29bbd78ea414c86402d4031855218dc42bTom Stellard#include <llvm/IR/DiagnosticPrinter.h> 2886100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <llvm/IR/DiagnosticInfo.h> 29aa1c734b3ca445b5af743b9bad6a48ca7ba21f3cTom Stellard#include <llvm/IR/LLVMContext.h> 3086100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <llvm/Support/raw_ostream.h> 3146a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard#include <llvm/Transforms/IPO/PassManagerBuilder.h> 328e7df519bd8556591794b2de08a833a67e34d526Tom Stellard#include <llvm-c/Target.h> 33c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez 3486100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/CodeGen/CodeGenAction.h> 35a73bf11a63ea93640c26b5701c533b06d3a6f3e9Tom Stellard#include <clang/Lex/PreprocessorOptions.h> 3686100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/Frontend/TextDiagnosticBuffer.h> 3786100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/Frontend/TextDiagnosticPrinter.h> 3886100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/Basic/TargetInfo.h> 39c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez 40106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// We need to include internal headers last, because the internal headers 41106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// include CL headers which have #define's like: 42106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// 43106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard//#define cl_khr_gl_sharing 1 44106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard//#define cl_khr_icd 1 45106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// 46106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// Which will break the compilation of clang/Basic/OpenCLOptions.h 47106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard 48106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "core/error.hpp" 49106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/codegen.hpp" 50106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/compat.hpp" 51106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/invocation.hpp" 52106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/metadata.hpp" 53106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/util.hpp" 54106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "util/algorithm.hpp" 55106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard 56106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard 57c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerezusing namespace clover; 58251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing namespace clover::llvm; 59251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez 60251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing ::llvm::Function; 61714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerezusing ::llvm::LLVMContext; 62251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing ::llvm::Module; 63251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing ::llvm::raw_string_ostream; 64c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez 65c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jereznamespace { 66714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez void 67714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez init_targets() { 68714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez static bool targets_initialized = false; 69714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez if (!targets_initialized) { 70714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez LLVMInitializeAllTargets(); 71714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez LLVMInitializeAllTargetInfos(); 72714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez LLVMInitializeAllTargetMCs(); 73714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez LLVMInitializeAllAsmPrinters(); 74714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez targets_initialized = true; 75714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez } 76714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez } 77714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez 78714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez void 79423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez diagnostic_handler(const ::llvm::DiagnosticInfo &di, void *data) { 80423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez if (di.getSeverity() == ::llvm::DS_Error) { 81423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez raw_string_ostream os { *reinterpret_cast<std::string *>(data) }; 82423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez ::llvm::DiagnosticPrinterRawOStream printer { os }; 83423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez di.print(printer); 844ef1c0918da4363aa20b7c1a91d344fae6c01942Francisco Jerez throw build_error(); 85714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez } 86714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez } 87714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez 88714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez std::unique_ptr<LLVMContext> 89714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez create_context(std::string &r_log) { 90714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez init_targets(); 91714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez std::unique_ptr<LLVMContext> ctx { new LLVMContext }; 92714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez ctx->setDiagnosticHandler(diagnostic_handler, &r_log); 93714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez return ctx; 94714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez } 95714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez 96a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez std::unique_ptr<clang::CompilerInstance> 97a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez create_compiler_instance(const target &target, 98a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez const std::vector<std::string> &opts, 99a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez std::string &r_log) { 100a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez std::unique_ptr<clang::CompilerInstance> c { new clang::CompilerInstance }; 101d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić clang::TextDiagnosticBuffer *diag_buffer = new clang::TextDiagnosticBuffer; 102a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez clang::DiagnosticsEngine diag { new clang::DiagnosticIDs, 103d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić new clang::DiagnosticOptions, diag_buffer }; 104a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 105a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez // Parse the compiler options. A file name should be present at the end 106a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez // and must have the .cl extension in order for the CompilerInvocation 107a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez // class to recognize it as an OpenCL source file. 108a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez const std::vector<const char *> copts = 109a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez map(std::mem_fn(&std::string::c_str), opts); 110a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 111a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez if (!clang::CompilerInvocation::CreateFromArgs( 112a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->getInvocation(), copts.data(), copts.data() + copts.size(), diag)) 1132a73ae662cb393bef0d2d0ab71bfd1072adbafb6Francisco Jerez throw invalid_build_options_error(); 114a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 115d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić diag_buffer->FlushDiagnostics(diag); 116d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić if (diag.hasErrorOccurred()) 117d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić throw invalid_build_options_error(); 118d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić 119a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->getTargetOpts().CPU = target.cpu; 120a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->getTargetOpts().Triple = target.triple; 121a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->getLangOpts().NoBuiltin = true; 122a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 123a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez // This is a workaround for a Clang bug which causes the number 124a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez // of warnings and errors to be printed to stderr. 125a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez // http://www.llvm.org/bugs/show_bug.cgi?id=19735 126a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->getDiagnosticOpts().ShowCarets = false; 127a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 128a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez compat::set_lang_defaults(c->getInvocation(), c->getLangOpts(), 129a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez clang::IK_OpenCL, ::llvm::Triple(target.triple), 130a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->getPreprocessorOpts(), 131a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez clang::LangStandard::lang_opencl11); 132a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 133a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->createDiagnostics(new clang::TextDiagnosticPrinter( 134a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez *new raw_string_ostream(r_log), 135a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez &c->getDiagnosticOpts(), true)); 136a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 137a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->setTarget(clang::TargetInfo::CreateTargetInfo( 138a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez c->getDiagnostics(), c->getInvocation().TargetOpts)); 139a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 140a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez return c; 141a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez } 142a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez 143bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez std::unique_ptr<Module> 144bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez compile(LLVMContext &ctx, clang::CompilerInstance &c, 145bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez const std::string &name, const std::string &source, 146bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez const header_map &headers, const std::string &target, 147bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez const std::string &opts, std::string &r_log) { 14846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; 14946a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard c.getHeaderSearchOpts().UseBuiltinIncludes = true; 15046a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard c.getHeaderSearchOpts().UseStandardSystemIncludes = true; 15146a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR; 15246a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 15346a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard // Add libclc generic search path 154959e83d65075513f989cb1fe634dca314a7e185fJohannes Obermayr c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR, 15546a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard clang::frontend::Angled, 156bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez false, false); 15746a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 15846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard // Add libclc include 15946a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard c.getPreprocessorOpts().Includes.push_back("clc/clc.h"); 16046a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 161cfa914a1b4e20e7ef416171f5212f21e8224befcNiels Ole Salscheider // Add definition for the OpenCL version 162cfa914a1b4e20e7ef416171f5212f21e8224befcNiels Ole Salscheider c.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=110"); 163cfa914a1b4e20e7ef416171f5212f21e8224befcNiels Ole Salscheider 16446a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard // clc.h requires that this macro be defined: 16546a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers"); 166bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez c.getPreprocessorOpts().addRemappedFile( 167bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez name, ::llvm::MemoryBuffer::getMemBuffer(source).release()); 16846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 169611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin if (headers.size()) { 170611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin const std::string tmp_header_path = "/tmp/clover/"; 171611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin 172611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin c.getHeaderSearchOpts().AddPath(tmp_header_path, 173611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin clang::frontend::Angled, 174bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez false, false); 175bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez 176bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez for (const auto &header : headers) 177bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez c.getPreprocessorOpts().addRemappedFile( 178bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez tmp_header_path + header.first, 179bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez ::llvm::MemoryBuffer::getMemBuffer(header.second).release()); 180611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin } 181611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin 182251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez // Tell clang to link this file before performing any 183251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez // optimizations. This is required so that we can replace calls 184251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez // to the OpenCL C barrier() builtin with calls to target 185251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez // intrinsics that have the noduplicate attribute. This 186251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez // attribute will prevent Clang from creating illegal uses of 187251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez // barrier() (e.g. Moving barrier() inside a conditional that is 188251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez // no executed by all threads) during its optimizaton passes. 189c513cfa747bdb9ac3059ab4e436cd7083c50aed0Francisco Jerez compat::add_link_bitcode_file(c.getCodeGenOpts(), 190c513cfa747bdb9ac3059ab4e436cd7083c50aed0Francisco Jerez LIBCLC_LIBEXECDIR + target + ".bc"); 191251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez 19246a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard // Compile the code 193bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez clang::EmitLLVMOnlyAction act(&ctx); 194a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez if (!c.ExecuteAction(act)) 1954ef1c0918da4363aa20b7c1a91d344fae6c01942Francisco Jerez throw build_error(); 19646a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 197bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez return act.takeModule(); 19846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard } 199132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez} 200132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez 201132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerezmodule 202132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerezclover::llvm::compile_program(const std::string &source, 203132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez const header_map &headers, 204132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez const std::string &target, 205132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez const std::string &opts, 206132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez std::string &r_log) { 207132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez if (has_flag(debug::clc)) 208132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez debug::log(".cl", "// Options: " + opts + '\n' + source); 20946a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 210132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez auto ctx = create_context(r_log); 211132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez auto c = create_compiler_instance(target, tokenize(opts + " input.cl"), 212132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez r_log); 213132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez auto mod = compile(*ctx, *c, "input.cl", source, headers, target, opts, 214132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez r_log); 215132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez 216132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez if (has_flag(debug::llvm)) 217132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez debug::log(".ll", print_module_bitcode(*mod)); 218132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez 219cc495055cdfe7e39002180d095d09fe4b6905eb9Serge Martin return build_module_library(*mod, module::section::text_intermediate); 220132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez} 221132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez 222132b6ccd4f81eac3cad5bef42325319708498240Francisco Jereznamespace { 223ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard void 224fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez optimize(Module &mod, unsigned optimization_level, 225fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez bool internalize_symbols) { 2265884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez compat::pass_manager pm; 22746a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 2285884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez compat::add_data_layout_pass(pm); 2297df256add2ae9fb916c3e0f80c879e42d1c8a7a0Shawn Starr 230ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // By default, the function internalizer pass will look for a function 231ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // called "main" and then mark all other functions as internal. Marking 232ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // functions as internal enables the optimizer to perform optimizations 233ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // like function inlining and global dead-code elimination. 234ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // 235ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // When there is no "main" function in a module, the internalize pass will 236ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // treat the module like a library, and it won't internalize any functions. 237ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // Since there is no "main" function in our kernels, we need to tell 238ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // the internalizer pass that this module is not a library by passing a 239ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // list of kernel functions to the internalizer. The internalizer will 240ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // treat the functions in the list as "main" functions and internalize 241ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard // all of the other functions. 242fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez if (internalize_symbols) 243fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez compat::add_internalize_pass(pm, map(std::mem_fn(&Function::getName), 244fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez get_kernels(mod))); 2455884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez 2465884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez ::llvm::PassManagerBuilder pmb; 2475884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez pmb.OptLevel = optimization_level; 2485884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez pmb.LibraryInfo = new compat::target_library_info( 2495884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez ::llvm::Triple(mod.getTargetTriple())); 2505884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez pmb.populateModulePassManager(pm); 2515884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez pm.run(mod); 25246a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard } 2539de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez 2549de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez std::unique_ptr<Module> 2559de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez link(LLVMContext &ctx, const clang::CompilerInstance &c, 2569de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez const std::vector<module> &modules, std::string &r_log) { 2579de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez std::unique_ptr<Module> mod { new Module("link", ctx) }; 2589de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez auto linker = compat::create_linker(*mod); 2599de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez 2609de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez for (auto &m : modules) { 2619de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez if (compat::link_in_module(*linker, 2629de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez parse_module_library(m, ctx, r_log))) 2634ef1c0918da4363aa20b7c1a91d344fae6c01942Francisco Jerez throw build_error(); 2649de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez } 2659de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez 2669de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez return std::move(mod); 2679de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez } 26886100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez} 269e1d363b3ffbfb85133a6871c63068a4ba841b2cdTom Stellard 270c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerezmodule 271132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerezclover::llvm::link_program(const std::vector<module> &modules, 272132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez enum pipe_shader_ir ir, const std::string &target, 273132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez const std::string &opts, std::string &r_log) { 274132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez std::vector<std::string> options = tokenize(opts + " input.cl"); 275fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez const bool create_library = count("-create-library", options); 276fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez erase_if(equals("-create-library"), options); 277fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez 278714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez auto ctx = create_context(r_log); 279132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez auto c = create_compiler_instance(target, options, r_log); 2809de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez auto mod = link(*ctx, *c, modules, r_log); 28146a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 282fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez optimize(*mod, c->getCodeGenOpts().OptimizationLevel, !create_library); 28346a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard 28426fa9bfd0dfccf06358180ae740121522d09b51fFrancisco Jerez if (has_flag(debug::llvm)) 28526fa9bfd0dfccf06358180ae740121522d09b51fFrancisco Jerez debug::log(".ll", print_module_bitcode(*mod)); 286e1d363b3ffbfb85133a6871c63068a4ba841b2cdTom Stellard 287fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez if (create_library) { 288cc495055cdfe7e39002180d095d09fe4b6905eb9Serge Martin return build_module_library(*mod, module::section::text_library); 289fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez 290fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez } else if (ir == PIPE_SHADER_IR_LLVM) { 291fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez return build_module_bitcode(*mod, *c); 292bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez 293fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez } else if (ir == PIPE_SHADER_IR_NATIVE) { 294fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez if (has_flag(debug::native)) 295fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez debug::log(".asm", print_module_native(*mod, target)); 296fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez 297fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez return build_module_native(*mod, target, *c, r_log); 298fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez 299fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez } else { 300fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez unreachable("Unsupported IR."); 301fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez } 302c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez} 303