Home | History | Annotate | Download | only in llvm-ndk-cc
      1 #include "Compiler.h"
      2 
      3 #include <cassert>
      4 #include <cstdlib>
      5 #include <string>
      6 #include <vector>
      7 
      8 #include "clang/AST/ASTConsumer.h"
      9 #include "clang/AST/ASTContext.h"
     10 
     11 #include "clang/Basic/DiagnosticIDs.h"
     12 #include "clang/Basic/FileManager.h"
     13 #include "clang/Basic/FileSystemOptions.h"
     14 #include "clang/Basic/LangOptions.h"
     15 #include "clang/Basic/SourceManager.h"
     16 #include "clang/Basic/TargetInfo.h"
     17 #include "clang/Basic/TargetOptions.h"
     18 
     19 #include "clang/Frontend/CodeGenOptions.h"
     20 #include "clang/Frontend/DiagnosticOptions.h"
     21 #include "clang/Frontend/DependencyOutputOptions.h"
     22 #include "clang/Frontend/CompilerInstance.h"
     23 #include "clang/Frontend/FrontendDiagnostic.h"
     24 #include "clang/Frontend/TextDiagnosticPrinter.h"
     25 #include "clang/Frontend/Utils.h"
     26 
     27 #include "clang/Lex/Preprocessor.h"
     28 #include "clang/Lex/HeaderSearch.h"
     29 
     30 #include "clang/Parse/ParseAST.h"
     31 
     32 #include "llvm/LLVMContext.h"
     33 
     34 #include "llvm/ADT/IntrusiveRefCntPtr.h"
     35 
     36 #include "llvm/Bitcode/ReaderWriter.h"
     37 
     38 #include "llvm/Support/raw_ostream.h"
     39 #include "llvm/Support/MemoryBuffer.h"
     40 #include "llvm/Support/ErrorHandling.h"
     41 #include "llvm/Support/ManagedStatic.h"
     42 #include "llvm/Support/ToolOutputFile.h"
     43 #include "llvm/Support/Path.h"
     44 
     45 #include "llvm/Support/TargetSelect.h"
     46 
     47 #include "Backend.h"
     48 
     49 namespace ndkpc {
     50 
     51 static inline llvm::tool_output_file *openOutputFile(const char *OutputFile,
     52                                                      unsigned Flags,
     53                                                      std::string* Error,
     54                                                      clang::DiagnosticsEngine* Diag) {
     55   assert((OutputFile != NULL) && (Error != NULL) && (Diag != NULL) &&
     56               "Invalid parameter!");
     57 
     58   llvm::tool_output_file *F =
     59         new llvm::tool_output_file(OutputFile, *Error, Flags);
     60   if (F != NULL)
     61     return F;
     62 
     63   // Report error here.
     64   Diag->Report(clang::diag::err_fe_error_opening) << OutputFile << *Error;
     65 
     66   return NULL;
     67 }
     68 
     69 void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) {
     70   clang::DiagnosticsEngine* Diags = static_cast<clang::DiagnosticsEngine*>(UserData);
     71   Diags->Report(clang::diag::err_fe_error_backend) << Message;
     72   exit(1);
     73 }
     74 
     75 void Compiler::createDiagnostic() {
     76   mpDiagClient = new clang::TextDiagnosticPrinter(llvm::errs(),
     77                                                  clang::DiagnosticOptions());
     78   mDiagIDs = new clang::DiagnosticIDs();
     79   mDiagnostics = new clang::DiagnosticsEngine(mDiagIDs, mpDiagClient);
     80   initDiagnostic();
     81   return;
     82 }
     83 
     84 void Compiler::createTarget(const std::string &Triple, const std::string &CPU,
     85                          const std::vector<std::string> &Features) {
     86   if (!Triple.empty())
     87     mTargetOpts.Triple = Triple;
     88   else
     89     mTargetOpts.Triple = llvm::Triple::normalize(DEFAULT_TARGET_TRIPLE_STRING);
     90 
     91   if (!CPU.empty())
     92     mTargetOpts.CPU = CPU;
     93 
     94   if (!Features.empty())
     95     mTargetOpts.Features = Features;
     96 
     97   mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagnostics,
     98                                                     mTargetOpts));
     99 
    100   return;
    101 }
    102 
    103 void Compiler::createFileManager() {
    104   mFileSysOpt.reset(new clang::FileSystemOptions());
    105   mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
    106 }
    107 
    108 void Compiler::createSourceManager() {
    109   mSourceMgr.reset(new clang::SourceManager(*mDiagnostics, *mFileMgr));
    110   return;
    111 }
    112 
    113 void Compiler::createPreprocessor() {
    114   clang::HeaderSearch *HS = new clang::HeaderSearch(*mFileMgr,
    115 						    *mDiagnostics,
    116 						    mLangOpts,
    117 						    mTarget.get());
    118 
    119   llvm::OwningPtr<clang::CompilerInstance> Clang(new clang::CompilerInstance());
    120 
    121   mPP.reset(new clang::Preprocessor(*mDiagnostics,
    122                                     mLangOpts,
    123                                     mTarget.get(),
    124                                     *mSourceMgr,
    125                                     *HS,
    126 				    *Clang,
    127                                     /* IILookup */0,
    128                                     /* OwnsHeaderSearch = */true,
    129                                     /*DelayInitialization=*/true));
    130 
    131   std::vector<clang::DirectoryLookup> SearchList;
    132   for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) {
    133     if (const clang::DirectoryEntry *DE =
    134             mFileMgr->getDirectory(mIncludePaths[i])) {
    135       SearchList.push_back(clang::DirectoryLookup(DE,
    136                                                   clang::SrcMgr::C_System,
    137                                                   false, /* isUser */
    138                                                   false /* isFramework */));
    139     }
    140   }
    141 
    142   HS->SetSearchPaths(SearchList, 0/* angledDirIdx FIXME CHECK */, 0/* systemDirIdx */, false/* noCurDirSearch */);
    143 
    144   initPreprocessor();
    145   return;
    146 }
    147 
    148 void Compiler::createASTContext() {
    149   mASTContext.reset(new clang::ASTContext(mLangOpts,
    150                                           *mSourceMgr,
    151                                           mTarget.get(),
    152                                           mPP->getIdentifierTable(),
    153                                           mPP->getSelectorTable(),
    154                                           mPP->getBuiltinInfo(),
    155                                           /* size_reserve = */0,
    156                                           /*DelayInitialization=*/true));
    157   initASTContext();
    158   return;
    159 }
    160 
    161 clang::ASTConsumer
    162 *Compiler::createBackend(const clang::CodeGenOptions& CodeGenOpts,
    163                       llvm::raw_ostream *OS,
    164                       OutputType OT) {
    165   return new Backend(CodeGenOpts,
    166                      mTargetOpts,
    167                      mDiagnostics.getPtr(),
    168                      OS,
    169                      OT);
    170 }
    171 
    172 Compiler::Compiler() : mInitialized(false), mpDiagClient(NULL), mOT(OT_Default) {
    173 }
    174 
    175 void Compiler::injectPreDefined() {
    176   typedef std::map<std::string, std::string> SymbolMapTy;
    177   for (SymbolMapTy::iterator
    178           it = mPreDefinedSymbolMap.begin(), et = mPreDefinedSymbolMap.end();
    179        it != et; ++it) {
    180     std::string Str = "#define "+it->first+" "+it->second+"\n";
    181     mPP->setPredefines(Str);
    182   }
    183 }
    184 
    185 void Compiler::init(const std::string &Triple, const std::string &CPU,
    186                     const std::vector<std::string> &Features, bool isCXX) {
    187   mLangOpts.RTTI = 0;  // Turn off the RTTI information support
    188   mLangOpts.C99 = 1;
    189   if (isCXX) {
    190     mLangOpts.CPlusPlus = 1;
    191   }
    192 
    193   mCodeGenOpts.OptimizationLevel = 3;  /* -O3 */
    194 
    195   createDiagnostic();
    196   llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.getPtr());
    197 
    198   createTarget(Triple, CPU, Features);
    199   createFileManager();
    200   createSourceManager();
    201 
    202   mInitialized = true;
    203 
    204   return;
    205 }
    206 
    207 bool Compiler::setInputSource(llvm::StringRef InputFile,
    208                               const char *Text,
    209                               size_t TextLength) {
    210   mInputFileName = InputFile.str();
    211 
    212   // Reset the ID tables if we are reusing the SourceManager
    213   mSourceMgr->clearIDTables();
    214 
    215   // Load the source
    216   llvm::MemoryBuffer *SB =
    217       llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength);
    218   mSourceMgr->createMainFileIDForMemBuffer(SB);
    219 
    220   if (mSourceMgr->getMainFileID().isInvalid()) {
    221     mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile;
    222     return false;
    223   }
    224   return true;
    225 }
    226 
    227 bool Compiler::setInputSource(llvm::StringRef InputFile) {
    228   mInputFileName = InputFile.str();
    229 
    230   mSourceMgr->clearIDTables();
    231 
    232   const clang::FileEntry *File = mFileMgr->getFile(InputFile);
    233   if (File)
    234     mSourceMgr->createMainFileID(File);
    235 
    236   if (mSourceMgr->getMainFileID().isInvalid()) {
    237     mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile;
    238     return false;
    239   }
    240 
    241   return true;
    242 }
    243 
    244 bool Compiler::setOutput(const char *OutputFile) {
    245   llvm::sys::Path OutputFilePath(OutputFile);
    246   std::string Error;
    247   llvm::tool_output_file *OS = NULL;
    248 
    249   switch (mOT) {
    250     case OT_Dependency:
    251     case OT_Assembly:
    252     case OT_LLVMAssembly: {
    253       OS = openOutputFile(OutputFile, 0, &Error, mDiagnostics.getPtr());
    254       break;
    255     }
    256     case OT_Nothing: {
    257       break;
    258     }
    259     case OT_Object:
    260     case OT_Bitcode: {
    261       OS = openOutputFile(OutputFile,
    262                           llvm::raw_fd_ostream::F_Binary,
    263                           &Error,
    264                           mDiagnostics.getPtr());
    265       break;
    266     }
    267     default: {
    268       llvm_unreachable("Unknown compiler output type");
    269     }
    270   }
    271 
    272   if (!Error.empty())
    273     return false;
    274 
    275   mOS.reset(OS);
    276 
    277   mOutputFileName = OutputFile;
    278 
    279   return true;
    280 }
    281 
    282 int Compiler::compile() {
    283   if (mDiagnostics->hasErrorOccurred())
    284     return 1;
    285   if (mOS.get() == NULL)
    286     return 1;
    287 
    288   // Here is per-compilation needed initialization
    289   createPreprocessor();
    290   createASTContext();
    291 
    292   mBackend.reset(createBackend(mCodeGenOpts, &mOS->os(), mOT));
    293 
    294   // Inform the diagnostic client we are processing a source file
    295   mpDiagClient->BeginSourceFile(mLangOpts, mPP.get());
    296 
    297   if (mLangOpts.CPlusPlus == 1) {
    298     mPP->setPredefines("#define __cplusplus\n");
    299   }
    300 
    301   this->injectPreDefined();
    302 
    303   // The core of the slang compiler
    304   ParseAST(*mPP, mBackend.get(), *mASTContext);
    305 
    306   // Inform the diagnostic client we are done with previous source file
    307   mpDiagClient->EndSourceFile();
    308 
    309   // Declare success if no error
    310   if (!mDiagnostics->hasErrorOccurred())
    311     mOS->keep();
    312 
    313   // The compilation ended, clear
    314   mBackend.reset();
    315   mASTContext.reset();
    316   mPP.reset();
    317   mOS.reset();
    318 
    319   return mDiagnostics->hasErrorOccurred() ? 1 : 0;
    320 }
    321 
    322 void Compiler::reset() {
    323   mDiagnostics->Reset();
    324   return;
    325 }
    326 
    327 Compiler::~Compiler() {
    328   llvm::llvm_shutdown();
    329   return;
    330 }
    331 
    332 }
    333