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