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