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