invocation.cpp revision 46a13b3b11d859e131399853c11ae2be0eb02f0a
1// 2// Copyright 2012 Francisco Jerez 3// 4// Permission is hereby granted, free of charge, to any person obtaining a 5// copy of this software and associated documentation files (the "Software"), 6// to deal in the Software without restriction, including without limitation 7// the rights to use, copy, modify, merge, publish, distribute, sublicense, 8// and/or sell copies of the Software, and to permit persons to whom the 9// Software is furnished to do so, subject to the following conditions: 10// 11// The above copyright notice and this permission notice shall be included in 12// all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17// THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20// SOFTWARE. 21// 22 23#include "core/compiler.hpp" 24 25#include <clang/Frontend/CompilerInstance.h> 26#include <clang/Frontend/TextDiagnosticPrinter.h> 27#include <clang/CodeGen/CodeGenAction.h> 28#include <llvm/Bitcode/BitstreamWriter.h> 29#include <llvm/Bitcode/ReaderWriter.h> 30#include <llvm/DerivedTypes.h> 31#include <llvm/Linker.h> 32#include <llvm/LLVMContext.h> 33#include <llvm/Module.h> 34#include <llvm/PassManager.h> 35#include <llvm/Support/TargetSelect.h> 36#include <llvm/Support/MemoryBuffer.h> 37#include <llvm/Support/PathV1.h> 38#include <llvm/Target/TargetData.h> 39#include <llvm/Transforms/IPO/PassManagerBuilder.h> 40 41#include "pipe/p_state.h" 42#include "util/u_memory.h" 43 44#include <iostream> 45#include <iomanip> 46#include <fstream> 47#include <cstdio> 48 49using namespace clover; 50 51namespace { 52#if 0 53 void 54 build_binary(const std::string &source, const std::string &target, 55 const std::string &name) { 56 clang::CompilerInstance c; 57 clang::EmitObjAction act(&llvm::getGlobalContext()); 58 std::string log; 59 llvm::raw_string_ostream s_log(log); 60 61 LLVMInitializeTGSITarget(); 62 LLVMInitializeTGSITargetInfo(); 63 LLVMInitializeTGSITargetMC(); 64 LLVMInitializeTGSIAsmPrinter(); 65 66 c.getFrontendOpts().Inputs.push_back( 67 std::make_pair(clang::IK_OpenCL, name)); 68 c.getHeaderSearchOpts().UseBuiltinIncludes = false; 69 c.getHeaderSearchOpts().UseStandardIncludes = false; 70 c.getLangOpts().NoBuiltin = true; 71 c.getTargetOpts().Triple = target; 72 c.getInvocation().setLangDefaults(clang::IK_OpenCL); 73 c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter( 74 s_log, c.getDiagnosticOpts())); 75 76 c.getPreprocessorOpts().addRemappedFile( 77 name, llvm::MemoryBuffer::getMemBuffer(source)); 78 79 if (!c.ExecuteAction(act)) 80 throw build_error(log); 81 } 82 83 module 84 load_binary(const char *name) { 85 std::ifstream fs((name)); 86 std::vector<unsigned char> str((std::istreambuf_iterator<char>(fs)), 87 (std::istreambuf_iterator<char>())); 88 compat::istream cs(str); 89 return module::deserialize(cs); 90 } 91#endif 92 93 llvm::Module * 94 compile(const std::string &source, const std::string &name, 95 const std::string &triple) { 96 97 clang::CompilerInstance c; 98 clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext()); 99 std::string log; 100 llvm::raw_string_ostream s_log(log); 101 102 c.getFrontendOpts().Inputs.push_back( 103 clang::FrontendInputFile(name, clang::IK_OpenCL)); 104 c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; 105 c.getHeaderSearchOpts().UseBuiltinIncludes = true; 106 c.getHeaderSearchOpts().UseStandardSystemIncludes = true; 107 c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR; 108 109 // Add libclc generic search path 110 c.getHeaderSearchOpts().AddPath(LIBCLC_PATH "/generic/include/", 111 clang::frontend::Angled, 112 false, false, false); 113 114 // Add libclc include 115 c.getPreprocessorOpts().Includes.push_back("clc/clc.h"); 116 117 // clc.h requires that this macro be defined: 118 c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers"); 119 120 c.getLangOpts().NoBuiltin = true; 121 c.getTargetOpts().Triple = triple; 122 c.getInvocation().setLangDefaults(clang::IK_OpenCL); 123 c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter( 124 s_log, c.getDiagnosticOpts())); 125 126 c.getPreprocessorOpts().addRemappedFile(name, 127 llvm::MemoryBuffer::getMemBuffer(source)); 128 129 // Compile the code 130 if (!c.ExecuteAction(act)) 131 throw build_error(log); 132 133 return act.takeModule(); 134 } 135 136 void 137 link(llvm::Module *mod, const std::string &triple) { 138 139 llvm::PassManager PM; 140 llvm::PassManagerBuilder Builder; 141 bool isNative; 142 llvm::Linker linker("clover", mod); 143 144 // Link the kernel with libclc 145 linker.LinkInFile(llvm::sys::Path(LIBCLC_PATH + triple + "/lib/builtins.bc"), isNative); 146 mod = linker.releaseModule(); 147 148 // Run link time optimizations 149 Builder.populateLTOPassManager(PM, false, true); 150 Builder.OptLevel = 2; 151 PM.run(*mod); 152 } 153 154 module 155 build_module_llvm(llvm::Module *mod) { 156 157 module m; 158 struct pipe_llvm_program_header header; 159 160 llvm::SmallVector<char, 1024> llvm_bitcode; 161 llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode); 162 llvm::BitstreamWriter writer(llvm_bitcode); 163 llvm::WriteBitcodeToFile(mod, bitcode_ostream); 164 bitcode_ostream.flush(); 165 166 std::string kernel_name; 167 compat::vector<module::argument> args; 168 const llvm::NamedMDNode *kernel_node = 169 mod->getNamedMetadata("opencl.kernels"); 170 // XXX: Support more than one kernel 171 assert(kernel_node->getNumOperands() <= 1); 172 173 llvm::Function *kernel_func = llvm::dyn_cast<llvm::Function>( 174 kernel_node->getOperand(0)->getOperand(0)); 175 kernel_name = kernel_func->getName(); 176 177 for (llvm::Function::arg_iterator I = kernel_func->arg_begin(), 178 E = kernel_func->arg_end(); I != E; ++I) { 179 llvm::Argument &arg = *I; 180 llvm::Type *arg_type = arg.getType(); 181 llvm::TargetData TD(kernel_func->getParent()); 182 unsigned arg_size = TD.getTypeStoreSize(arg_type); 183 184 if (llvm::isa<llvm::PointerType>(arg_type) && arg.hasByValAttr()) { 185 arg_type = 186 llvm::dyn_cast<llvm::PointerType>(arg_type)->getElementType(); 187 } 188 189 if (arg_type->isPointerTy()) { 190 // XXX: Figure out LLVM->OpenCL address space mappings for each 191 // target. I think we need to ask clang what these are. For now, 192 // pretend everything is in the global address space. 193 unsigned address_space = llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace(); 194 switch (address_space) { 195 default: 196 args.push_back(module::argument(module::argument::global, arg_size)); 197 break; 198 } 199 } else { 200 args.push_back(module::argument(module::argument::scalar, arg_size)); 201 } 202 } 203 204 header.num_bytes = llvm_bitcode.size(); 205 std::string data; 206 data.insert(0, (char*)(&header), sizeof(header)); 207 data.insert(data.end(), llvm_bitcode.begin(), 208 llvm_bitcode.end()); 209 m.syms.push_back(module::symbol(kernel_name, 0, 0, args )); 210 m.secs.push_back(module::section(0, module::section::text, 211 header.num_bytes, data)); 212 213 return m; 214 } 215} // End anonymous namespace 216 217module 218clover::compile_program_llvm(const compat::string &source, 219 enum pipe_shader_ir ir, 220 const compat::string &triple) { 221 222 llvm::Module *mod = compile(source, "cl_input", triple); 223 224 link(mod, triple); 225 226 // Build the clover::module 227 switch (ir) { 228 case PIPE_SHADER_IR_TGSI: 229 //XXX: Handle TGSI 230 assert(0); 231 return module(); 232 default: 233 return build_module_llvm(mod); 234 } 235} 236