• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
getGlobalLLVMContext()129  llvm::LLVMContext &getGlobalLLVMContext() { return globalContext; }
130  
131  static inline std::unique_ptr<llvm::tool_output_file>
OpenOutputFile(const char * OutputFile,llvm::sys::fs::OpenFlags Flags,std::error_code & EC,clang::DiagnosticsEngine * DiagEngine)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  
createTarget(uint32_t BitWidth)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  
createFileManager()163  void Slang::createFileManager() {
164    mFileSysOpt.reset(new clang::FileSystemOptions());
165    mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
166  }
167  
createSourceManager()168  void Slang::createSourceManager() {
169    mSourceMgr.reset(new clang::SourceManager(*mDiagEngine, *mFileMgr));
170  }
171  
createPreprocessor()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  
createASTContext()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 *
createBackend(const RSCCOptions & Opts,const clang::CodeGenOptions & CodeGenOpts,llvm::raw_ostream * OS,OutputType OT)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  
Slang(uint32_t BitWidth,clang::DiagnosticsEngine * DiagEngine,DiagnosticBuffer * DiagClient)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  
~Slang()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  
loadModule(clang::SourceLocation ImportLoc,clang::ModuleIdPath Path,clang::Module::NameVisibilityKind Visibility,bool IsInclusionDirective)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  
setInputSource(llvm::StringRef InputFile)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  
setOutput(const char * OutputFile)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  
setDepOutput(const char * OutputFile)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  
generateDepFile(bool PhonyTarget)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  
compile(const RSCCOptions & Opts)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  
setDebugMetadataEmission(bool EmitDebug)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  
setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel)442  void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) {
443    CodeGenOpts.OptimizationLevel = OptimizationLevel;
444  }
445  
isFilterscript(const char * Filename)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  
generateJavaBitcodeAccessor(const std::string & OutputPathBase,const std::string & PackageName,const std::string * LicenseNote)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  
checkODR(const char * CurInputFile)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  
initPreprocessor()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  
initASTContext()537  void Slang::initASTContext() {
538    mRSContext = new RSContext(getPreprocessor(),
539                               getASTContext(),
540                               getTargetInfo(),
541                               &mPragmas,
542                               mTargetAPI,
543                               mVerbose);
544  }
545  
IsRSHeaderFile(const char * File)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  
IsLocInRSHeaderFile(const clang::SourceLocation & Loc,const clang::SourceManager & SourceMgr)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  
compile(const std::list<std::pair<const char *,const char * >> & IOFiles64,const std::list<std::pair<const char *,const char * >> & IOFiles32,const std::list<std::pair<const char *,const char * >> & DepFiles,const RSCCOptions & Opts,clang::DiagnosticOptions & DiagOpts,ReflectionState * RState)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,
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