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 *
OpenOutputFile(const char * OutputFile,llvm::sys::fs::OpenFlags Flags,std::error_code & EC,clang::DiagnosticsEngine * DiagEngine)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 
createTarget(uint32_t BitWidth)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 
createFileManager()167 void Slang::createFileManager() {
168   mFileSysOpt.reset(new clang::FileSystemOptions());
169   mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
170 }
171 
createSourceManager()172 void Slang::createSourceManager() {
173   mSourceMgr.reset(new clang::SourceManager(*mDiagEngine, *mFileMgr));
174 }
175 
createPreprocessor()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 
createASTContext()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 *
createBackend(const RSCCOptions & Opts,const clang::CodeGenOptions & CodeGenOpts,llvm::raw_ostream * OS,OutputType OT)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 
Slang(uint32_t BitWidth,clang::DiagnosticsEngine * DiagEngine,DiagnosticBuffer * DiagClient)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 
~Slang()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 
loadModule(clang::SourceLocation ImportLoc,clang::ModuleIdPath Path,clang::Module::NameVisibilityKind Visibility,bool IsInclusionDirective)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 
setInputSource(llvm::StringRef InputFile)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 
setOutput(const char * OutputFile)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 
setDepOutput(const char * OutputFile)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 
generateDepFile(bool PhonyTarget)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 
compile(const RSCCOptions & Opts)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 
setDebugMetadataEmission(bool EmitDebug)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 
setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel)447 void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) {
448   CodeGenOpts.OptimizationLevel = OptimizationLevel;
449 }
450 
isFilterscript(const char * Filename)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 
generateJavaBitcodeAccessor(const std::string & OutputPathBase,const std::string & PackageName,const std::string * LicenseNote)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 
checkODR(const char * CurInputFile)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 
initPreprocessor()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 
initASTContext()577 void Slang::initASTContext() {
578   mRSContext = new RSContext(getPreprocessor(),
579                              getASTContext(),
580                              getTargetInfo(),
581                              &mPragmas,
582                              mTargetAPI,
583                              mVerbose);
584 }
585 
IsRSHeaderFile(const char * File)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 
IsLocInRSHeaderFile(const clang::SourceLocation & Loc,const clang::SourceManager & SourceMgr)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 
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)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