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