Home | History | Annotate | Download | only in llvm
      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