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 <cstring>
     22 #include <list>
     23 #include <sstream>
     24 #include <string>
     25 #include <utility>
     26 #include <vector>
     27 
     28 #include "clang/AST/ASTConsumer.h"
     29 #include "clang/AST/ASTContext.h"
     30 
     31 #include "clang/Basic/DiagnosticIDs.h"
     32 #include "clang/Basic/DiagnosticOptions.h"
     33 #include "clang/Basic/FileManager.h"
     34 #include "clang/Basic/FileSystemOptions.h"
     35 #include "clang/Basic/SourceLocation.h"
     36 #include "clang/Basic/SourceManager.h"
     37 #include "clang/Basic/TargetInfo.h"
     38 #include "clang/Basic/TargetOptions.h"
     39 
     40 #include "clang/Frontend/DependencyOutputOptions.h"
     41 #include "clang/Frontend/FrontendDiagnostic.h"
     42 #include "clang/Frontend/FrontendOptions.h"
     43 #include "clang/Frontend/PCHContainerOperations.h"
     44 #include "clang/Frontend/TextDiagnosticPrinter.h"
     45 #include "clang/Frontend/Utils.h"
     46 
     47 #include "clang/Lex/HeaderSearch.h"
     48 #include "clang/Lex/HeaderSearchOptions.h"
     49 #include "clang/Lex/Preprocessor.h"
     50 #include "clang/Lex/PreprocessorOptions.h"
     51 
     52 #include "clang/Parse/ParseAST.h"
     53 
     54 #include "clang/Sema/SemaDiagnostic.h"
     55 
     56 #include "llvm/ADT/IntrusiveRefCntPtr.h"
     57 
     58 #include "llvm/Bitcode/ReaderWriter.h"
     59 
     60 // More force linking
     61 #include "llvm/Linker/Linker.h"
     62 
     63 // Force linking all passes/vmcore stuffs to libslang.so
     64 #include "llvm/LinkAllIR.h"
     65 #include "llvm/LinkAllPasses.h"
     66 
     67 #include "llvm/Support/raw_ostream.h"
     68 #include "llvm/Support/MemoryBuffer.h"
     69 #include "llvm/Support/ErrorHandling.h"
     70 #include "llvm/Support/ManagedStatic.h"
     71 #include "llvm/Support/Path.h"
     72 #include "llvm/Support/TargetSelect.h"
     73 #include "llvm/Support/ToolOutputFile.h"
     74 
     75 #include "os_sep.h"
     76 #include "rs_cc_options.h"
     77 #include "slang_assert.h"
     78 #include "slang_backend.h"
     79 
     80 #include "slang_rs_context.h"
     81 #include "slang_rs_export_type.h"
     82 
     83 #include "slang_rs_reflection.h"
     84 #include "slang_rs_reflection_cpp.h"
     85 
     86 
     87 namespace {
     88 
     89 static const char *kRSTriple32 = "armv7-none-linux-gnueabi";
     90 static const char *kRSTriple64 = "aarch64-none-linux-gnueabi";
     91 
     92 }  // namespace
     93 
     94 namespace slang {
     95 
     96 
     97 #define FS_SUFFIX  "fs"
     98 
     99 #define RS_HEADER_SUFFIX  "rsh"
    100 
    101 /* RS_HEADER_ENTRY(name) */
    102 #define ENUM_RS_HEADER()  \
    103   RS_HEADER_ENTRY(rs_allocation_create) \
    104   RS_HEADER_ENTRY(rs_allocation_data) \
    105   RS_HEADER_ENTRY(rs_atomic) \
    106   RS_HEADER_ENTRY(rs_convert) \
    107   RS_HEADER_ENTRY(rs_core) \
    108   RS_HEADER_ENTRY(rs_debug) \
    109   RS_HEADER_ENTRY(rs_for_each) \
    110   RS_HEADER_ENTRY(rs_graphics) \
    111   RS_HEADER_ENTRY(rs_graphics_types) \
    112   RS_HEADER_ENTRY(rs_io) \
    113   RS_HEADER_ENTRY(rs_math) \
    114   RS_HEADER_ENTRY(rs_matrix) \
    115   RS_HEADER_ENTRY(rs_object_info) \
    116   RS_HEADER_ENTRY(rs_object_types) \
    117   RS_HEADER_ENTRY(rs_quaternion) \
    118   RS_HEADER_ENTRY(rs_time) \
    119   RS_HEADER_ENTRY(rs_value_types) \
    120   RS_HEADER_ENTRY(rs_vector_math) \
    121 
    122 
    123 // The named of metadata node that pragma resides (should be synced with
    124 // bcc.cpp)
    125 const llvm::StringRef Slang::PragmaMetadataName = "#pragma";
    126 
    127 static inline llvm::tool_output_file *
    128 OpenOutputFile(const char *OutputFile,
    129                llvm::sys::fs::OpenFlags Flags,
    130                std::error_code &EC,
    131                clang::DiagnosticsEngine *DiagEngine) {
    132   slangAssert((OutputFile != nullptr) &&
    133               (DiagEngine != nullptr) && "Invalid parameter!");
    134 
    135   EC = llvm::sys::fs::create_directories(
    136       llvm::sys::path::parent_path(OutputFile));
    137   if (!EC) {
    138     llvm::tool_output_file *F =
    139           new llvm::tool_output_file(OutputFile, EC, Flags);
    140     if (F != nullptr)
    141       return F;
    142   }
    143 
    144   // Report error here.
    145   DiagEngine->Report(clang::diag::err_fe_error_opening)
    146     << OutputFile << EC.message();
    147 
    148   return nullptr;
    149 }
    150 
    151 void Slang::createTarget(uint32_t BitWidth) {
    152   std::vector<std::string> features;
    153 
    154   if (BitWidth == 64) {
    155     mTargetOpts->Triple = kRSTriple64;
    156   } else {
    157     mTargetOpts->Triple = kRSTriple32;
    158     // Treat long as a 64-bit type for our 32-bit RS code.
    159     features.push_back("+long64");
    160     mTargetOpts->FeaturesAsWritten = features;
    161   }
    162 
    163   mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagEngine,
    164                                                     mTargetOpts));
    165 }
    166 
    167 void Slang::createFileManager() {
    168   mFileSysOpt.reset(new clang::FileSystemOptions());
    169   mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
    170 }
    171 
    172 void Slang::createSourceManager() {
    173   mSourceMgr.reset(new clang::SourceManager(*mDiagEngine, *mFileMgr));
    174 }
    175 
    176 void Slang::createPreprocessor() {
    177   // Default only search header file in current dir
    178   clang::HeaderSearch *HeaderInfo = new clang::HeaderSearch(&getHeaderSearchOpts(),
    179                                                             *mSourceMgr,
    180                                                             *mDiagEngine,
    181                                                             LangOpts,
    182                                                             mTarget.get());
    183 
    184   mPP.reset(new clang::Preprocessor(&getPreprocessorOpts(),
    185                                     *mDiagEngine,
    186                                     LangOpts,
    187                                     *mSourceMgr,
    188                                     *HeaderInfo,
    189                                     *this,
    190                                     nullptr,
    191                                     /* OwnsHeaderSearch = */true));
    192   // Initialize the preprocessor
    193   mPP->Initialize(getTargetInfo());
    194   clang::FrontendOptions FEOpts;
    195 
    196   auto *Reader = mPCHContainerOperations->getReaderOrNull(
    197       getHeaderSearchOpts().ModuleFormat);
    198   clang::InitializePreprocessor(*mPP, getPreprocessorOpts(), *Reader, FEOpts);
    199 
    200   clang::ApplyHeaderSearchOptions(*HeaderInfo, getHeaderSearchOpts(), LangOpts,
    201       mPP->getTargetInfo().getTriple());
    202 
    203   mPragmas.clear();
    204 
    205   std::vector<clang::DirectoryLookup> SearchList;
    206   for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) {
    207     if (const clang::DirectoryEntry *DE =
    208             mFileMgr->getDirectory(mIncludePaths[i])) {
    209       SearchList.push_back(clang::DirectoryLookup(DE,
    210                                                   clang::SrcMgr::C_System,
    211                                                   false));
    212     }
    213   }
    214 
    215   HeaderInfo->SetSearchPaths(SearchList,
    216                              /* angledDirIdx = */1,
    217                              /* systemDixIdx = */1,
    218                              /* noCurDirSearch = */false);
    219 
    220   initPreprocessor();
    221 }
    222 
    223 void Slang::createASTContext() {
    224   mASTContext.reset(
    225       new clang::ASTContext(LangOpts, *mSourceMgr, mPP->getIdentifierTable(),
    226                             mPP->getSelectorTable(), mPP->getBuiltinInfo()));
    227   mASTContext->InitBuiltinTypes(getTargetInfo());
    228   initASTContext();
    229 }
    230 
    231 clang::ASTConsumer *
    232 Slang::createBackend(const RSCCOptions &Opts, const clang::CodeGenOptions &CodeGenOpts,
    233                      llvm::raw_ostream *OS, OutputType OT) {
    234   auto *B = new Backend(mRSContext, &getDiagnostics(), Opts,
    235                         getHeaderSearchOpts(), getPreprocessorOpts(),
    236                         CodeGenOpts, getTargetOptions(), &mPragmas, OS, OT,
    237                         getSourceManager(), mAllowRSPrefix, mIsFilterscript);
    238   B->Initialize(getASTContext());
    239   return B;
    240 }
    241 
    242 Slang::Slang(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine,
    243              DiagnosticBuffer *DiagClient)
    244     : mDiagEngine(DiagEngine), mDiagClient(DiagClient),
    245       mTargetOpts(new clang::TargetOptions()),
    246       mHSOpts(new clang::HeaderSearchOptions()),
    247       mPPOpts(new clang::PreprocessorOptions()),
    248       mPCHContainerOperations(std::make_shared<clang::PCHContainerOperations>()),
    249       mOT(OT_Default), mRSContext(nullptr), mAllowRSPrefix(false), mTargetAPI(0),
    250       mVerbose(false), mIsFilterscript(false) {
    251   // Please refer to include/clang/Basic/LangOptions.h to setup
    252   // the options.
    253   LangOpts.RTTI = 0;  // Turn off the RTTI information support
    254   LangOpts.LineComment = 1;
    255   LangOpts.C99 = 1;
    256   LangOpts.Renderscript = 1;
    257   LangOpts.LaxVectorConversions = 0;  // Do not bitcast vectors!
    258   LangOpts.CharIsSigned = 1;  // Signed char is our default.
    259 
    260   CodeGenOpts.OptimizationLevel = 3;
    261 
    262   // We must set StackRealignment, because the default is for the actual
    263   // Clang driver to pass this option (-mstackrealign) directly to cc1.
    264   // Since we don't use Clang's driver, we need to similarly supply it.
    265   // If StackRealignment is zero (i.e. the option wasn't set), then the
    266   // backend assumes that it can't adjust the stack in any way, which breaks
    267   // alignment for vector loads/stores.
    268   CodeGenOpts.StackRealignment = 1;
    269 
    270   createTarget(BitWidth);
    271   createFileManager();
    272   createSourceManager();
    273 }
    274 
    275 Slang::~Slang() {
    276   delete mRSContext;
    277   for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(),
    278                                            E = ReflectedDefinitions.end();
    279        I != E; I++) {
    280     delete I->getValue().first;
    281   }
    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   mInputFileName = InputFile.str();
    295 
    296   mSourceMgr->clearIDTables();
    297 
    298   const clang::FileEntry *File = mFileMgr->getFile(InputFile);
    299   if (File) {
    300     mSourceMgr->setMainFileID(mSourceMgr->createFileID(File,
    301         clang::SourceLocation(), clang::SrcMgr::C_User));
    302   }
    303 
    304   if (mSourceMgr->getMainFileID().isInvalid()) {
    305     mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile;
    306     return false;
    307   }
    308 
    309   return true;
    310 }
    311 
    312 bool Slang::setOutput(const char *OutputFile) {
    313   std::error_code EC;
    314   llvm::tool_output_file *OS = nullptr;
    315 
    316   switch (mOT) {
    317     case OT_Dependency:
    318     case OT_Assembly:
    319     case OT_LLVMAssembly: {
    320       OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, EC, mDiagEngine);
    321       break;
    322     }
    323     case OT_Nothing: {
    324       break;
    325     }
    326     case OT_Object:
    327     case OT_Bitcode: {
    328       OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_None, EC, mDiagEngine);
    329       break;
    330     }
    331     default: {
    332       llvm_unreachable("Unknown compiler output type");
    333     }
    334   }
    335 
    336   if (EC)
    337     return false;
    338 
    339   mOS.reset(OS);
    340 
    341   mOutputFileName = OutputFile;
    342 
    343   return true;
    344 }
    345 
    346 bool Slang::setDepOutput(const char *OutputFile) {
    347   std::error_code EC;
    348 
    349   mDOS.reset(
    350       OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, EC, mDiagEngine));
    351   if (EC || (mDOS.get() == nullptr))
    352     return false;
    353 
    354   mDepOutputFileName = OutputFile;
    355 
    356   return true;
    357 }
    358 
    359 int Slang::generateDepFile(bool PhonyTarget) {
    360   if (mDiagEngine->hasErrorOccurred())
    361     return 1;
    362   if (mDOS.get() == nullptr)
    363     return 1;
    364 
    365   // Initialize options for generating dependency file
    366   clang::DependencyOutputOptions DepOpts;
    367   DepOpts.IncludeSystemHeaders = 1;
    368   if (PhonyTarget)
    369     DepOpts.UsePhonyTargets = 1;
    370   DepOpts.OutputFile = mDepOutputFileName;
    371   DepOpts.Targets = mAdditionalDepTargets;
    372   DepOpts.Targets.push_back(mDepTargetBCFileName);
    373   for (std::vector<std::string>::const_iterator
    374            I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end();
    375        I != E;
    376        I++) {
    377     DepOpts.Targets.push_back(*I);
    378   }
    379   mGeneratedFileNames.clear();
    380 
    381   // Per-compilation needed initialization
    382   createPreprocessor();
    383   clang::DependencyFileGenerator::CreateAndAttachToPreprocessor(*mPP.get(), DepOpts);
    384 
    385   // Inform the diagnostic client we are processing a source file
    386   mDiagClient->BeginSourceFile(LangOpts, mPP.get());
    387 
    388   // Go through the source file (no operations necessary)
    389   clang::Token Tok;
    390   mPP->EnterMainSourceFile();
    391   do {
    392     mPP->Lex(Tok);
    393   } while (Tok.isNot(clang::tok::eof));
    394 
    395   mPP->EndSourceFile();
    396 
    397   // Declare success if no error
    398   if (!mDiagEngine->hasErrorOccurred())
    399     mDOS->keep();
    400 
    401   // Clean up after compilation
    402   mPP.reset();
    403   mDOS.reset();
    404 
    405   return mDiagEngine->hasErrorOccurred() ? 1 : 0;
    406 }
    407 
    408 int Slang::compile(const RSCCOptions &Opts) {
    409   if (mDiagEngine->hasErrorOccurred())
    410     return 1;
    411   if (mOS.get() == nullptr)
    412     return 1;
    413 
    414   // Here is per-compilation needed initialization
    415   createPreprocessor();
    416   createASTContext();
    417 
    418   mBackend.reset(createBackend(Opts, CodeGenOpts, &mOS->os(), mOT));
    419 
    420   // Inform the diagnostic client we are processing a source file
    421   mDiagClient->BeginSourceFile(LangOpts, mPP.get());
    422 
    423   // The core of the slang compiler
    424   ParseAST(*mPP, mBackend.get(), *mASTContext);
    425 
    426   // Inform the diagnostic client we are done with previous source file
    427   mDiagClient->EndSourceFile();
    428 
    429   // Declare success if no error
    430   if (!mDiagEngine->hasErrorOccurred())
    431     mOS->keep();
    432 
    433   // The compilation ended, clear
    434   mBackend.reset();
    435   mOS.reset();
    436 
    437   return mDiagEngine->hasErrorOccurred() ? 1 : 0;
    438 }
    439 
    440 void Slang::setDebugMetadataEmission(bool EmitDebug) {
    441   if (EmitDebug)
    442     CodeGenOpts.setDebugInfo(clang::CodeGenOptions::FullDebugInfo);
    443   else
    444     CodeGenOpts.setDebugInfo(clang::CodeGenOptions::NoDebugInfo);
    445 }
    446 
    447 void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) {
    448   CodeGenOpts.OptimizationLevel = OptimizationLevel;
    449 }
    450 
    451 bool Slang::isFilterscript(const char *Filename) {
    452   const char *c = strrchr(Filename, '.');
    453   if (c && !strncmp(FS_SUFFIX, c + 1, strlen(FS_SUFFIX) + 1)) {
    454     return true;
    455   } else {
    456     return false;
    457   }
    458 }
    459 
    460 bool Slang::generateJavaBitcodeAccessor(const std::string &OutputPathBase,
    461                                           const std::string &PackageName,
    462                                           const std::string *LicenseNote) {
    463   RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
    464 
    465   BCAccessorContext.rsFileName = getInputFileName().c_str();
    466   BCAccessorContext.bc32FileName = mOutput32FileName.c_str();
    467   BCAccessorContext.bc64FileName = mOutputFileName.c_str();
    468   BCAccessorContext.reflectPath = OutputPathBase.c_str();
    469   BCAccessorContext.packageName = PackageName.c_str();
    470   BCAccessorContext.licenseNote = LicenseNote;
    471   BCAccessorContext.bcStorage = BCST_JAVA_CODE;   // Must be BCST_JAVA_CODE
    472   BCAccessorContext.verbose = false;
    473 
    474   return RSSlangReflectUtils::GenerateJavaBitCodeAccessor(BCAccessorContext);
    475 }
    476 
    477 bool Slang::checkODR(const char *CurInputFile) {
    478   for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(),
    479           E = mRSContext->exportable_end();
    480        I != E;
    481        I++) {
    482     RSExportable *RSE = *I;
    483     if (RSE->getKind() != RSExportable::EX_TYPE)
    484       continue;
    485 
    486     RSExportType *ET = static_cast<RSExportType *>(RSE);
    487     if (ET->getClass() != RSExportType::ExportClassRecord)
    488       continue;
    489 
    490     RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET);
    491 
    492     // Artificial record types (create by us not by user in the source) always
    493     // conforms the ODR.
    494     if (ERT->isArtificial())
    495       continue;
    496 
    497     // Key to lookup ERT in ReflectedDefinitions
    498     llvm::StringRef RDKey(ERT->getName());
    499     ReflectedDefinitionListTy::const_iterator RD =
    500         ReflectedDefinitions.find(RDKey);
    501 
    502     if (RD != ReflectedDefinitions.end()) {
    503       const RSExportRecordType *Reflected = RD->getValue().first;
    504       // There's a record (struct) with the same name reflected before. Enforce
    505       // ODR checking - the Reflected must hold *exactly* the same "definition"
    506       // as the one defined previously. We say two record types A and B have the
    507       // same definition iff:
    508       //
    509       //  struct A {              struct B {
    510       //    Type(a1) a1,            Type(b1) b1,
    511       //    Type(a2) a2,            Type(b1) b2,
    512       //    ...                     ...
    513       //    Type(aN) aN             Type(b3) b3,
    514       //  };                      }
    515       //  Cond. #1. They have same number of fields, i.e., N = M;
    516       //  Cond. #2. for (i := 1 to N)
    517       //              Type(ai) = Type(bi) must hold;
    518       //  Cond. #3. for (i := 1 to N)
    519       //              Name(ai) = Name(bi) must hold;
    520       //
    521       // where,
    522       //  Type(F) = the type of field F and
    523       //  Name(F) = the field name.
    524 
    525       bool PassODR = false;
    526       // Cond. #1 and Cond. #2
    527       if (Reflected->equals(ERT)) {
    528         // Cond #3.
    529         RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(),
    530                                                  BI = ERT->fields_begin();
    531 
    532         for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) {
    533           if ((*AI)->getName() != (*BI)->getName())
    534             break;
    535           AI++;
    536           BI++;
    537         }
    538         PassODR = (AI == (Reflected->fields_end()));
    539       }
    540 
    541       if (!PassODR) {
    542         unsigned DiagID = mDiagEngine->getCustomDiagID(
    543             clang::DiagnosticsEngine::Error,
    544             "type '%0' in different translation unit (%1 v.s. %2) "
    545             "has incompatible type definition");
    546         getDiagnostics().Report(DiagID) << Reflected->getName()
    547                                         << getInputFileName()
    548                                         << RD->getValue().second;
    549         return false;
    550       }
    551     } else {
    552       llvm::StringMapEntry<ReflectedDefinitionTy> *ME =
    553           llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey);
    554       ME->setValue(std::make_pair(ERT, CurInputFile));
    555 
    556       if (!ReflectedDefinitions.insert(ME)) {
    557         slangAssert(false && "Type shouldn't be in map yet!");
    558       }
    559 
    560       // Take the ownership of ERT such that it won't be freed in ~RSContext().
    561       ERT->keep();
    562     }
    563   }
    564   return true;
    565 }
    566 
    567 void Slang::initPreprocessor() {
    568   clang::Preprocessor &PP = getPreprocessor();
    569 
    570   std::stringstream RSH;
    571   RSH << PP.getPredefines();
    572   RSH << "#define RS_VERSION " << mTargetAPI << "\n";
    573   RSH << "#include \"rs_core." RS_HEADER_SUFFIX "\"\n";
    574   PP.setPredefines(RSH.str());
    575 }
    576 
    577 void Slang::initASTContext() {
    578   mRSContext = new RSContext(getPreprocessor(),
    579                              getASTContext(),
    580                              getTargetInfo(),
    581                              &mPragmas,
    582                              mTargetAPI,
    583                              mVerbose);
    584 }
    585 
    586 bool Slang::IsRSHeaderFile(const char *File) {
    587 #define RS_HEADER_ENTRY(name)  \
    588   if (::strcmp(File, #name "." RS_HEADER_SUFFIX) == 0)  \
    589     return true;
    590 ENUM_RS_HEADER()
    591 #undef RS_HEADER_ENTRY
    592   return false;
    593 }
    594 
    595 bool Slang::IsLocInRSHeaderFile(const clang::SourceLocation &Loc,
    596                                   const clang::SourceManager &SourceMgr) {
    597   clang::FullSourceLoc FSL(Loc, SourceMgr);
    598   clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL);
    599 
    600   const char *Filename = PLoc.getFilename();
    601   if (!Filename) {
    602     return false;
    603   } else {
    604     return IsRSHeaderFile(llvm::sys::path::filename(Filename).data());
    605   }
    606 }
    607 
    608 bool Slang::compile(
    609     const std::list<std::pair<const char*, const char*> > &IOFiles64,
    610     const std::list<std::pair<const char*, const char*> > &IOFiles32,
    611     const std::list<std::pair<const char*, const char*> > &DepFiles,
    612     const RSCCOptions &Opts,
    613     clang::DiagnosticOptions &DiagOpts) {
    614   if (IOFiles32.empty())
    615     return true;
    616 
    617   if (Opts.mEmitDependency && (DepFiles.size() != IOFiles32.size())) {
    618     unsigned DiagID = mDiagEngine->getCustomDiagID(
    619         clang::DiagnosticsEngine::Error,
    620         "invalid parameter for output dependencies files.");
    621     getDiagnostics().Report(DiagID);
    622     return false;
    623   }
    624 
    625   if (Opts.mEmit3264 && (IOFiles64.size() != IOFiles32.size())) {
    626     slangAssert(false && "Should have equal number of 32/64-bit files");
    627     return false;
    628   }
    629 
    630   std::string RealPackageName;
    631 
    632   const char *InputFile, *Output64File, *Output32File, *BCOutputFile,
    633              *DepOutputFile;
    634 
    635   setIncludePaths(Opts.mIncludePaths);
    636   setOutputType(Opts.mOutputType);
    637   if (Opts.mEmitDependency) {
    638     setAdditionalDepTargets(Opts.mAdditionalDepTargets);
    639   }
    640 
    641   setDebugMetadataEmission(Opts.mDebugEmission);
    642 
    643   setOptimizationLevel(Opts.mOptimizationLevel);
    644 
    645   mAllowRSPrefix = Opts.mAllowRSPrefix;
    646 
    647   mTargetAPI = Opts.mTargetAPI;
    648   if (mTargetAPI != SLANG_DEVELOPMENT_TARGET_API &&
    649       (mTargetAPI < SLANG_MINIMUM_TARGET_API ||
    650        mTargetAPI > SLANG_MAXIMUM_TARGET_API)) {
    651     unsigned DiagID = mDiagEngine->getCustomDiagID(
    652         clang::DiagnosticsEngine::Error,
    653         "target API level '%0' is out of range ('%1' - '%2')");
    654     getDiagnostics().Report(DiagID) << mTargetAPI << SLANG_MINIMUM_TARGET_API
    655                                     << SLANG_MAXIMUM_TARGET_API;
    656     return false;
    657   }
    658 
    659   if (mTargetAPI >= SLANG_M_TARGET_API) {
    660     LangOpts.NativeHalfType = 1;
    661     LangOpts.HalfArgsAndReturns = 1;
    662   }
    663 
    664   mVerbose = Opts.mVerbose;
    665 
    666   // Skip generation of warnings a second time if we are doing more than just
    667   // a single pass over the input file.
    668   bool SuppressAllWarnings = (Opts.mOutputType != Slang::OT_Dependency);
    669 
    670   std::list<std::pair<const char*, const char*> >::const_iterator
    671       IOFile64Iter = IOFiles64.begin(),
    672       IOFile32Iter = IOFiles32.begin(),
    673       DepFileIter = DepFiles.begin();
    674 
    675   for (unsigned i = 0, e = IOFiles32.size(); i != e; i++) {
    676     InputFile = IOFile64Iter->first;
    677     Output64File = IOFile64Iter->second;
    678     Output32File = IOFile32Iter->second;
    679 
    680     if (!setInputSource(InputFile))
    681       return false;
    682 
    683     if (!setOutput(Output64File))
    684       return false;
    685 
    686     // For use with 64-bit compilation/reflection. This only sets the filename of
    687     // the 32-bit bitcode file, and doesn't actually verify it already exists.
    688     mOutput32FileName = Output32File;
    689 
    690     mIsFilterscript = isFilterscript(InputFile);
    691 
    692     CodeGenOpts.MainFileName = mInputFileName;
    693 
    694     if (Slang::compile(Opts) > 0)
    695       return false;
    696 
    697     if (!Opts.mJavaReflectionPackageName.empty()) {
    698       mRSContext->setReflectJavaPackageName(Opts.mJavaReflectionPackageName);
    699     }
    700     const std::string &RealPackageName =
    701         mRSContext->getReflectJavaPackageName();
    702 
    703     bool doReflection = true;
    704     if (Opts.mEmit3264 && (Opts.mBitWidth == 32)) {
    705       // Skip reflection on the 32-bit path if we are going to emit it on the
    706       // 64-bit path.
    707       doReflection = false;
    708     }
    709     if (Opts.mOutputType != Slang::OT_Dependency && doReflection) {
    710 
    711       if (Opts.mBitcodeStorage == BCST_CPP_CODE) {
    712         const std::string &outputFileName = (Opts.mBitWidth == 64) ?
    713                                             mOutputFileName : mOutput32FileName;
    714         RSReflectionCpp R(mRSContext, Opts.mJavaReflectionPathBase,
    715                           getInputFileName(), outputFileName);
    716         if (!R.reflect()) {
    717             return false;
    718         }
    719       } else {
    720         if (!Opts.mRSPackageName.empty()) {
    721           mRSContext->setRSPackageName(Opts.mRSPackageName);
    722         }
    723 
    724         std::vector<std::string> generatedFileNames;
    725         RSReflectionJava R(mRSContext, &generatedFileNames,
    726                            Opts.mJavaReflectionPathBase, getInputFileName(),
    727                            mOutputFileName,
    728                            Opts.mBitcodeStorage == BCST_JAVA_CODE);
    729         if (!R.reflect()) {
    730           // TODO Is this needed or will the error message have been printed
    731           // already? and why not for the C++ case?
    732           fprintf(stderr, "RSContext::reflectToJava : failed to do reflection "
    733                           "(%s)\n",
    734                   R.getLastError());
    735           return false;
    736         }
    737 
    738         for (std::vector<std::string>::const_iterator
    739                  I = generatedFileNames.begin(), E = generatedFileNames.end();
    740              I != E;
    741              I++) {
    742           std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath(
    743               Opts.mJavaReflectionPathBase.c_str(),
    744               (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str());
    745           appendGeneratedFileName(ReflectedName + ".java");
    746         }
    747 
    748         if ((Opts.mOutputType == Slang::OT_Bitcode) &&
    749             (Opts.mBitcodeStorage == BCST_JAVA_CODE) &&
    750             !generateJavaBitcodeAccessor(Opts.mJavaReflectionPathBase,
    751                                          RealPackageName.c_str(),
    752                                          mRSContext->getLicenseNote())) {
    753           return false;
    754         }
    755       }
    756     }
    757 
    758     if (Opts.mEmitDependency) {
    759       BCOutputFile = DepFileIter->first;
    760       DepOutputFile = DepFileIter->second;
    761 
    762       setDepTargetBC(BCOutputFile);
    763 
    764       if (!setDepOutput(DepOutputFile))
    765         return false;
    766 
    767       if (SuppressAllWarnings) {
    768         getDiagnostics().setSuppressAllDiagnostics(true);
    769       }
    770       if (generateDepFile(Opts.mEmitPhonyDependency) > 0)
    771         return false;
    772       if (SuppressAllWarnings) {
    773         getDiagnostics().setSuppressAllDiagnostics(false);
    774       }
    775 
    776       DepFileIter++;
    777     }
    778 
    779     if (!checkODR(InputFile))
    780       return false;
    781 
    782     IOFile64Iter++;
    783     IOFile32Iter++;
    784   }
    785   return true;
    786 }
    787 
    788 }  // namespace slang
    789