Home | History | Annotate | Download | only in slang
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "slang.h"
     18 
     19 #include <stdlib.h>
     20 
     21 #include <string>
     22 #include <vector>
     23 
     24 #include "clang/AST/ASTConsumer.h"
     25 #include "clang/AST/ASTContext.h"
     26 
     27 #include "clang/Basic/DiagnosticIDs.h"
     28 #include "clang/Basic/DiagnosticOptions.h"
     29 #include "clang/Basic/FileManager.h"
     30 #include "clang/Basic/FileSystemOptions.h"
     31 #include "clang/Basic/LangOptions.h"
     32 #include "clang/Basic/SourceManager.h"
     33 #include "clang/Basic/TargetInfo.h"
     34 #include "clang/Basic/TargetOptions.h"
     35 
     36 #include "clang/Frontend/CodeGenOptions.h"
     37 #include "clang/Frontend/DependencyOutputOptions.h"
     38 #include "clang/Frontend/FrontendDiagnostic.h"
     39 #include "clang/Frontend/FrontendOptions.h"
     40 #include "clang/Frontend/TextDiagnosticPrinter.h"
     41 #include "clang/Frontend/Utils.h"
     42 
     43 #include "clang/Lex/Preprocessor.h"
     44 #include "clang/Lex/PreprocessorOptions.h"
     45 #include "clang/Lex/HeaderSearch.h"
     46 #include "clang/Lex/HeaderSearchOptions.h"
     47 
     48 #include "clang/Parse/ParseAST.h"
     49 
     50 #include "llvm/ADT/IntrusiveRefCntPtr.h"
     51 
     52 #include "llvm/Bitcode/ReaderWriter.h"
     53 
     54 // More force linking
     55 #include "llvm/Linker/Linker.h"
     56 
     57 // Force linking all passes/vmcore stuffs to libslang.so
     58 #include "llvm/LinkAllIR.h"
     59 #include "llvm/LinkAllPasses.h"
     60 
     61 #include "llvm/Support/raw_ostream.h"
     62 #include "llvm/Support/MemoryBuffer.h"
     63 #include "llvm/Support/ErrorHandling.h"
     64 #include "llvm/Support/ManagedStatic.h"
     65 #include "llvm/Support/Path.h"
     66 #include "llvm/Support/TargetSelect.h"
     67 #include "llvm/Support/ToolOutputFile.h"
     68 
     69 #include "slang_assert.h"
     70 #include "slang_backend.h"
     71 #include "slang_utils.h"
     72 
     73 namespace {
     74 
     75 static const char *kRSTriple32 = "armv7-none-linux-gnueabi";
     76 static const char *kRSTriple64 = "aarch64-none-linux-gnueabi";
     77 
     78 struct ForceSlangLinking {
     79   ForceSlangLinking() {
     80     // We must reference the functions in such a way that compilers will not
     81     // delete it all as dead code, even with whole program optimization,
     82     // yet is effectively a NO-OP. As the compiler isn't smart enough
     83     // to know that getenv() never returns -1, this will do the job.
     84     if (std::getenv("bar") != reinterpret_cast<char*>(-1))
     85       return;
     86 
     87     // llvm-rs-link needs following functions existing in libslang.
     88     llvm::parseBitcodeFile(NULL, llvm::getGlobalContext());
     89     llvm::Linker::LinkModules(NULL, NULL, 0, NULL);
     90 
     91     // llvm-rs-cc need this.
     92     new clang::TextDiagnosticPrinter(llvm::errs(),
     93                                      new clang::DiagnosticOptions());
     94   }
     95 } ForceSlangLinking;
     96 
     97 }  // namespace
     98 
     99 namespace slang {
    100 
    101 bool Slang::GlobalInitialized = false;
    102 
    103 // Language option (define the language feature for compiler such as C99)
    104 clang::LangOptions Slang::LangOpts;
    105 
    106 // Code generation option for the compiler
    107 clang::CodeGenOptions Slang::CodeGenOpts;
    108 
    109 // The named of metadata node that pragma resides (should be synced with
    110 // bcc.cpp)
    111 const llvm::StringRef Slang::PragmaMetadataName = "#pragma";
    112 
    113 static inline llvm::tool_output_file *
    114 OpenOutputFile(const char *OutputFile,
    115                llvm::sys::fs::OpenFlags Flags,
    116                std::string* Error,
    117                clang::DiagnosticsEngine *DiagEngine) {
    118   slangAssert((OutputFile != NULL) && (Error != NULL) &&
    119               (DiagEngine != NULL) && "Invalid parameter!");
    120 
    121   if (SlangUtils::CreateDirectoryWithParents(
    122                         llvm::sys::path::parent_path(OutputFile), Error)) {
    123     llvm::tool_output_file *F =
    124           new llvm::tool_output_file(OutputFile, *Error, Flags);
    125     if (F != NULL)
    126       return F;
    127   }
    128 
    129   // Report error here.
    130   DiagEngine->Report(clang::diag::err_fe_error_opening)
    131     << OutputFile << *Error;
    132 
    133   return NULL;
    134 }
    135 
    136 void Slang::GlobalInitialization() {
    137   if (!GlobalInitialized) {
    138     // We only support x86, x64 and ARM target
    139 
    140     // For ARM
    141     LLVMInitializeARMTargetInfo();
    142     LLVMInitializeARMTarget();
    143     LLVMInitializeARMAsmPrinter();
    144 
    145     // For x86 and x64
    146     LLVMInitializeX86TargetInfo();
    147     LLVMInitializeX86Target();
    148     LLVMInitializeX86AsmPrinter();
    149 
    150     // Please refer to include/clang/Basic/LangOptions.h to setup
    151     // the options.
    152     LangOpts.RTTI = 0;  // Turn off the RTTI information support
    153     LangOpts.C99 = 1;
    154     LangOpts.Renderscript = 1;
    155     LangOpts.LaxVectorConversions = 0;  // Do not bitcast vectors!
    156     LangOpts.CharIsSigned = 1;  // Signed char is our default.
    157 
    158     CodeGenOpts.OptimizationLevel = 3;
    159 
    160     GlobalInitialized = true;
    161   }
    162 }
    163 
    164 void Slang::LLVMErrorHandler(void *UserData, const std::string &Message,
    165                              bool GenCrashDialog) {
    166   clang::DiagnosticsEngine* DiagEngine =
    167     static_cast<clang::DiagnosticsEngine *>(UserData);
    168 
    169   DiagEngine->Report(clang::diag::err_fe_error_backend) << Message;
    170   exit(1);
    171 }
    172 
    173 void Slang::createTarget(uint32_t BitWidth) {
    174   std::vector<std::string> features;
    175 
    176   if (BitWidth == 64) {
    177     mTargetOpts->Triple = kRSTriple64;
    178   } else {
    179     mTargetOpts->Triple = kRSTriple32;
    180     // Treat long as a 64-bit type for our 32-bit RS code.
    181     features.push_back("+long64");
    182     mTargetOpts->FeaturesAsWritten = features;
    183   }
    184 
    185   mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagEngine,
    186                                                     mTargetOpts));
    187 }
    188 
    189 void Slang::createFileManager() {
    190   mFileSysOpt.reset(new clang::FileSystemOptions());
    191   mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
    192 }
    193 
    194 void Slang::createSourceManager() {
    195   mSourceMgr.reset(new clang::SourceManager(*mDiagEngine, *mFileMgr));
    196 }
    197 
    198 void Slang::createPreprocessor() {
    199   // Default only search header file in current dir
    200   llvm::IntrusiveRefCntPtr<clang::HeaderSearchOptions> HSOpts =
    201       new clang::HeaderSearchOptions();
    202   clang::HeaderSearch *HeaderInfo = new clang::HeaderSearch(HSOpts,
    203                                                             *mSourceMgr,
    204                                                             *mDiagEngine,
    205                                                             LangOpts,
    206                                                             mTarget.get());
    207 
    208   llvm::IntrusiveRefCntPtr<clang::PreprocessorOptions> PPOpts =
    209       new clang::PreprocessorOptions();
    210   mPP.reset(new clang::Preprocessor(PPOpts,
    211                                     *mDiagEngine,
    212                                     LangOpts,
    213                                     *mSourceMgr,
    214                                     *HeaderInfo,
    215                                     *this,
    216                                     NULL,
    217                                     /* OwnsHeaderSearch = */true));
    218   // Initialize the preprocessor
    219   mPP->Initialize(getTargetInfo());
    220   clang::FrontendOptions FEOpts;
    221   clang::InitializePreprocessor(*mPP, *PPOpts, FEOpts);
    222 
    223   mPragmas.clear();
    224   mPP->AddPragmaHandler(new PragmaRecorder(&mPragmas));
    225 
    226   std::vector<clang::DirectoryLookup> SearchList;
    227   for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) {
    228     if (const clang::DirectoryEntry *DE =
    229             mFileMgr->getDirectory(mIncludePaths[i])) {
    230       SearchList.push_back(clang::DirectoryLookup(DE,
    231                                                   clang::SrcMgr::C_System,
    232                                                   false));
    233     }
    234   }
    235 
    236   HeaderInfo->SetSearchPaths(SearchList,
    237                              /* angledDirIdx = */1,
    238                              /* systemDixIdx = */1,
    239                              /* noCurDirSearch = */false);
    240 
    241   initPreprocessor();
    242 }
    243 
    244 void Slang::createASTContext() {
    245   mASTContext.reset(new clang::ASTContext(LangOpts,
    246                                           *mSourceMgr,
    247                                           mPP->getIdentifierTable(),
    248                                           mPP->getSelectorTable(),
    249                                           mPP->getBuiltinInfo()));
    250   mASTContext->InitBuiltinTypes(getTargetInfo());
    251   initASTContext();
    252 }
    253 
    254 clang::ASTConsumer *
    255 Slang::createBackend(const clang::CodeGenOptions& CodeGenOpts,
    256                      llvm::raw_ostream *OS, OutputType OT) {
    257   return new Backend(mDiagEngine, CodeGenOpts, getTargetOptions(),
    258                      &mPragmas, OS, OT);
    259 }
    260 
    261 Slang::Slang() : mInitialized(false), mDiagClient(NULL),
    262   mTargetOpts(new clang::TargetOptions()), mOT(OT_Default) {
    263   GlobalInitialization();
    264 }
    265 
    266 void Slang::init(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine,
    267                  DiagnosticBuffer *DiagClient) {
    268   if (mInitialized)
    269     return;
    270 
    271   mDiagEngine = DiagEngine;
    272   mDiagClient = DiagClient;
    273   mDiag.reset(new clang::Diagnostic(mDiagEngine));
    274   initDiagnostic();
    275   llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagEngine);
    276 
    277   createTarget(BitWidth);
    278   createFileManager();
    279   createSourceManager();
    280 
    281   mInitialized = true;
    282 }
    283 
    284 clang::ModuleLoadResult Slang::loadModule(
    285     clang::SourceLocation ImportLoc,
    286     clang::ModuleIdPath Path,
    287     clang::Module::NameVisibilityKind Visibility,
    288     bool IsInclusionDirective) {
    289   slangAssert(0 && "Not implemented");
    290   return clang::ModuleLoadResult();
    291 }
    292 
    293 bool Slang::setInputSource(llvm::StringRef InputFile,
    294                            const char *Text,
    295                            size_t TextLength) {
    296   mInputFileName = InputFile.str();
    297 
    298   // Reset the ID tables if we are reusing the SourceManager
    299   mSourceMgr->clearIDTables();
    300 
    301   // Load the source
    302   llvm::MemoryBuffer *SB =
    303       llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength);
    304   mSourceMgr->setMainFileID(mSourceMgr->createFileID(SB));
    305 
    306   if (mSourceMgr->getMainFileID().isInvalid()) {
    307     mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile;
    308     return false;
    309   }
    310   return true;
    311 }
    312 
    313 bool Slang::setInputSource(llvm::StringRef InputFile) {
    314   mInputFileName = InputFile.str();
    315 
    316   mSourceMgr->clearIDTables();
    317 
    318   const clang::FileEntry *File = mFileMgr->getFile(InputFile);
    319   if (File) {
    320     mSourceMgr->setMainFileID(mSourceMgr->createFileID(File,
    321         clang::SourceLocation(), clang::SrcMgr::C_User));
    322   }
    323 
    324   if (mSourceMgr->getMainFileID().isInvalid()) {
    325     mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile;
    326     return false;
    327   }
    328 
    329   return true;
    330 }
    331 
    332 bool Slang::setOutput(const char *OutputFile) {
    333   std::string Error;
    334   llvm::tool_output_file *OS = NULL;
    335 
    336   switch (mOT) {
    337     case OT_Dependency:
    338     case OT_Assembly:
    339     case OT_LLVMAssembly: {
    340       OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, &Error,
    341           mDiagEngine);
    342       break;
    343     }
    344     case OT_Nothing: {
    345       break;
    346     }
    347     case OT_Object:
    348     case OT_Bitcode: {
    349       OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_None,
    350                           &Error, mDiagEngine);
    351       break;
    352     }
    353     default: {
    354       llvm_unreachable("Unknown compiler output type");
    355     }
    356   }
    357 
    358   if (!Error.empty())
    359     return false;
    360 
    361   mOS.reset(OS);
    362 
    363   mOutputFileName = OutputFile;
    364 
    365   return true;
    366 }
    367 
    368 bool Slang::setDepOutput(const char *OutputFile) {
    369   std::string Error;
    370 
    371   mDOS.reset(
    372       OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, &Error, mDiagEngine));
    373   if (!Error.empty() || (mDOS.get() == NULL))
    374     return false;
    375 
    376   mDepOutputFileName = OutputFile;
    377 
    378   return true;
    379 }
    380 
    381 int Slang::generateDepFile() {
    382   if (mDiagEngine->hasErrorOccurred())
    383     return 1;
    384   if (mDOS.get() == NULL)
    385     return 1;
    386 
    387   // Initialize options for generating dependency file
    388   clang::DependencyOutputOptions DepOpts;
    389   DepOpts.IncludeSystemHeaders = 1;
    390   DepOpts.OutputFile = mDepOutputFileName;
    391   DepOpts.Targets = mAdditionalDepTargets;
    392   DepOpts.Targets.push_back(mDepTargetBCFileName);
    393   for (std::vector<std::string>::const_iterator
    394            I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end();
    395        I != E;
    396        I++) {
    397     DepOpts.Targets.push_back(*I);
    398   }
    399   mGeneratedFileNames.clear();
    400 
    401   // Per-compilation needed initialization
    402   createPreprocessor();
    403   clang::DependencyFileGenerator::CreateAndAttachToPreprocessor(*mPP.get(), DepOpts);
    404 
    405   // Inform the diagnostic client we are processing a source file
    406   mDiagClient->BeginSourceFile(LangOpts, mPP.get());
    407 
    408   // Go through the source file (no operations necessary)
    409   clang::Token Tok;
    410   mPP->EnterMainSourceFile();
    411   do {
    412     mPP->Lex(Tok);
    413   } while (Tok.isNot(clang::tok::eof));
    414 
    415   mPP->EndSourceFile();
    416 
    417   // Declare success if no error
    418   if (!mDiagEngine->hasErrorOccurred())
    419     mDOS->keep();
    420 
    421   // Clean up after compilation
    422   mPP.reset();
    423   mDOS.reset();
    424 
    425   return mDiagEngine->hasErrorOccurred() ? 1 : 0;
    426 }
    427 
    428 int Slang::compile() {
    429   if (mDiagEngine->hasErrorOccurred())
    430     return 1;
    431   if (mOS.get() == NULL)
    432     return 1;
    433 
    434   // Here is per-compilation needed initialization
    435   createPreprocessor();
    436   createASTContext();
    437 
    438   mBackend.reset(createBackend(CodeGenOpts, &mOS->os(), mOT));
    439 
    440   // Inform the diagnostic client we are processing a source file
    441   mDiagClient->BeginSourceFile(LangOpts, mPP.get());
    442 
    443   // The core of the slang compiler
    444   ParseAST(*mPP, mBackend.get(), *mASTContext);
    445 
    446   // Inform the diagnostic client we are done with previous source file
    447   mDiagClient->EndSourceFile();
    448 
    449   // Declare success if no error
    450   if (!mDiagEngine->hasErrorOccurred())
    451     mOS->keep();
    452 
    453   // The compilation ended, clear
    454   mBackend.reset();
    455   mASTContext.reset();
    456   mPP.reset();
    457   mOS.reset();
    458 
    459   return mDiagEngine->hasErrorOccurred() ? 1 : 0;
    460 }
    461 
    462 void Slang::setDebugMetadataEmission(bool EmitDebug) {
    463   if (EmitDebug)
    464     CodeGenOpts.setDebugInfo(clang::CodeGenOptions::FullDebugInfo);
    465   else
    466     CodeGenOpts.setDebugInfo(clang::CodeGenOptions::NoDebugInfo);
    467 }
    468 
    469 void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) {
    470   CodeGenOpts.OptimizationLevel = OptimizationLevel;
    471 }
    472 
    473 void Slang::reset(bool SuppressWarnings) {
    474   // Always print diagnostics if we had an error occur, but don't print
    475   // warnings if we suppressed them (i.e. we are doing the 64-bit compile after
    476   // an existing 32-bit compile).
    477   //
    478   // TODO: This should really be removing duplicate identical warnings between
    479   // the 32-bit and 64-bit compiles, but that is a more substantial feature.
    480   // Bug: 17052573
    481   if (!SuppressWarnings || mDiagEngine->hasErrorOccurred()) {
    482     llvm::errs() << mDiagClient->str();
    483   }
    484   mDiagEngine->Reset();
    485   mDiagClient->reset();
    486 }
    487 
    488 Slang::~Slang() {
    489 }
    490 
    491 }  // namespace slang
    492