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.h> 40 #include <llvm/Transforms/IPO/PassManagerBuilder.h> 41 42 #include "pipe/p_state.h" 43 #include "util/u_memory.h" 44 45 #include <iostream> 46 #include <iomanip> 47 #include <fstream> 48 #include <cstdio> 49 50 using namespace clover; 51 52 namespace { 53 #if 0 54 void 55 build_binary(const std::string &source, const std::string &target, 56 const std::string &name) { 57 clang::CompilerInstance c; 58 clang::EmitObjAction act(&llvm::getGlobalContext()); 59 std::string log; 60 llvm::raw_string_ostream s_log(log); 61 62 LLVMInitializeTGSITarget(); 63 LLVMInitializeTGSITargetInfo(); 64 LLVMInitializeTGSITargetMC(); 65 LLVMInitializeTGSIAsmPrinter(); 66 67 c.getFrontendOpts().Inputs.push_back( 68 std::make_pair(clang::IK_OpenCL, name)); 69 c.getHeaderSearchOpts().UseBuiltinIncludes = false; 70 c.getHeaderSearchOpts().UseStandardIncludes = false; 71 c.getLangOpts().NoBuiltin = true; 72 c.getTargetOpts().Triple = target; 73 c.getInvocation().setLangDefaults(clang::IK_OpenCL); 74 c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter( 75 s_log, c.getDiagnosticOpts())); 76 77 c.getPreprocessorOpts().addRemappedFile( 78 name, llvm::MemoryBuffer::getMemBuffer(source)); 79 80 if (!c.ExecuteAction(act)) 81 throw build_error(log); 82 } 83 84 module 85 load_binary(const char *name) { 86 std::ifstream fs((name)); 87 std::vector<unsigned char> str((std::istreambuf_iterator<char>(fs)), 88 (std::istreambuf_iterator<char>())); 89 compat::istream cs(str); 90 return module::deserialize(cs); 91 } 92 #endif 93 94 llvm::Module * 95 compile(const std::string &source, const std::string &name, 96 const std::string &triple) { 97 98 clang::CompilerInstance c; 99 clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext()); 100 std::string log; 101 llvm::raw_string_ostream s_log(log); 102 103 c.getFrontendOpts().Inputs.push_back( 104 clang::FrontendInputFile(name, clang::IK_OpenCL)); 105 c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; 106 c.getHeaderSearchOpts().UseBuiltinIncludes = true; 107 c.getHeaderSearchOpts().UseStandardSystemIncludes = true; 108 c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR; 109 110 // Add libclc generic search path 111 c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR, 112 clang::frontend::Angled, 113 false, false, false); 114 115 // Add libclc include 116 c.getPreprocessorOpts().Includes.push_back("clc/clc.h"); 117 118 // clc.h requires that this macro be defined: 119 c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers"); 120 121 c.getLangOpts().NoBuiltin = true; 122 c.getTargetOpts().Triple = triple; 123 c.getInvocation().setLangDefaults(clang::IK_OpenCL); 124 c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter( 125 s_log, c.getDiagnosticOpts())); 126 127 c.getPreprocessorOpts().addRemappedFile(name, 128 llvm::MemoryBuffer::getMemBuffer(source)); 129 130 // Compile the code 131 if (!c.ExecuteAction(act)) 132 throw build_error(log); 133 134 return act.takeModule(); 135 } 136 137 void 138 find_kernels(llvm::Module *mod, std::vector<llvm::Function *> &kernels) { 139 const llvm::NamedMDNode *kernel_node = 140 mod->getNamedMetadata("opencl.kernels"); 141 for (unsigned i = 0; i < kernel_node->getNumOperands(); ++i) { 142 kernels.push_back(llvm::dyn_cast<llvm::Function>( 143 kernel_node->getOperand(i)->getOperand(0))); 144 } 145 } 146 147 void 148 link(llvm::Module *mod, const std::string &triple, 149 const std::vector<llvm::Function *> &kernels) { 150 151 llvm::PassManager PM; 152 llvm::PassManagerBuilder Builder; 153 bool isNative; 154 llvm::Linker linker("clover", mod); 155 156 // Link the kernel with libclc 157 linker.LinkInFile(llvm::sys::Path(LIBCLC_LIBEXECDIR + triple + ".bc"), isNative); 158 mod = linker.releaseModule(); 159 160 // Add a function internalizer pass. 161 // 162 // By default, the function internalizer pass will look for a function 163 // called "main" and then mark all other functions as internal. Marking 164 // functions as internal enables the optimizer to perform optimizations 165 // like function inlining and global dead-code elimination. 166 // 167 // When there is no "main" function in a module, the internalize pass will 168 // treat the module like a library, and it won't internalize any functions. 169 // Since there is no "main" function in our kernels, we need to tell 170 // the internalizer pass that this module is not a library by passing a 171 // list of kernel functions to the internalizer. The internalizer will 172 // treat the functions in the list as "main" functions and internalize 173 // all of the other functions. 174 std::vector<const char*> export_list; 175 for (std::vector<llvm::Function *>::const_iterator I = kernels.begin(), 176 E = kernels.end(); 177 I != E; ++I) { 178 llvm::Function *kernel = *I; 179 export_list.push_back(kernel->getName().data()); 180 } 181 PM.add(llvm::createInternalizePass(export_list)); 182 183 // Run link time optimizations 184 Builder.OptLevel = 2; 185 Builder.populateLTOPassManager(PM, false, true); 186 PM.run(*mod); 187 } 188 189 module 190 build_module_llvm(llvm::Module *mod, 191 const std::vector<llvm::Function *> &kernels) { 192 193 module m; 194 struct pipe_llvm_program_header header; 195 196 llvm::SmallVector<char, 1024> llvm_bitcode; 197 llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode); 198 llvm::BitstreamWriter writer(llvm_bitcode); 199 llvm::WriteBitcodeToFile(mod, bitcode_ostream); 200 bitcode_ostream.flush(); 201 202 llvm::Function *kernel_func; 203 std::string kernel_name; 204 compat::vector<module::argument> args; 205 206 // XXX: Support more than one kernel 207 assert(kernels.size() == 1); 208 209 kernel_func = kernels[0]; 210 kernel_name = kernel_func->getName(); 211 212 for (llvm::Function::arg_iterator I = kernel_func->arg_begin(), 213 E = kernel_func->arg_end(); I != E; ++I) { 214 llvm::Argument &arg = *I; 215 llvm::Type *arg_type = arg.getType(); 216 llvm::TargetData TD(kernel_func->getParent()); 217 unsigned arg_size = TD.getTypeStoreSize(arg_type); 218 219 if (llvm::isa<llvm::PointerType>(arg_type) && arg.hasByValAttr()) { 220 arg_type = 221 llvm::dyn_cast<llvm::PointerType>(arg_type)->getElementType(); 222 } 223 224 if (arg_type->isPointerTy()) { 225 // XXX: Figure out LLVM->OpenCL address space mappings for each 226 // target. I think we need to ask clang what these are. For now, 227 // pretend everything is in the global address space. 228 unsigned address_space = llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace(); 229 switch (address_space) { 230 default: 231 args.push_back(module::argument(module::argument::global, arg_size)); 232 break; 233 } 234 } else { 235 args.push_back(module::argument(module::argument::scalar, arg_size)); 236 } 237 } 238 239 header.num_bytes = llvm_bitcode.size(); 240 std::string data; 241 data.insert(0, (char*)(&header), sizeof(header)); 242 data.insert(data.end(), llvm_bitcode.begin(), 243 llvm_bitcode.end()); 244 m.syms.push_back(module::symbol(kernel_name, 0, 0, args )); 245 m.secs.push_back(module::section(0, module::section::text, 246 header.num_bytes, data)); 247 248 return m; 249 } 250 } // End anonymous namespace 251 252 module 253 clover::compile_program_llvm(const compat::string &source, 254 enum pipe_shader_ir ir, 255 const compat::string &triple) { 256 257 std::vector<llvm::Function *> kernels; 258 259 llvm::Module *mod = compile(source, "cl_input", triple); 260 261 find_kernels(mod, kernels); 262 263 link(mod, triple, kernels); 264 265 // Build the clover::module 266 switch (ir) { 267 case PIPE_SHADER_IR_TGSI: 268 //XXX: Handle TGSI 269 assert(0); 270 return module(); 271 default: 272 return build_module_llvm(mod, kernels); 273 } 274 } 275