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
87namespace {
88
89static const char *kRSTriple32 = "armv7-none-linux-gnueabi";
90static const char *kRSTriple64 = "aarch64-none-linux-gnueabi";
91
92}  // namespace
93
94namespace 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)
125const llvm::StringRef Slang::PragmaMetadataName = "#pragma";
126
127static inline llvm::tool_output_file *
128OpenOutputFile(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
151void 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
167void Slang::createFileManager() {
168  mFileSysOpt.reset(new clang::FileSystemOptions());
169  mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
170}
171
172void Slang::createSourceManager() {
173  mSourceMgr.reset(new clang::SourceManager(*mDiagEngine, *mFileMgr));
174}
175
176void 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
223void 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
231clang::ASTConsumer *
232Slang::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
242Slang::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
275Slang::~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
284clang::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
293bool 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
312bool 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
346bool 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
359int 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
408int 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
440void Slang::setDebugMetadataEmission(bool EmitDebug) {
441  if (EmitDebug)
442    CodeGenOpts.setDebugInfo(clang::CodeGenOptions::FullDebugInfo);
443  else
444    CodeGenOpts.setDebugInfo(clang::CodeGenOptions::NoDebugInfo);
445}
446
447void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) {
448  CodeGenOpts.OptimizationLevel = OptimizationLevel;
449}
450
451bool 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
460bool 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
477bool 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
567void 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
577void Slang::initASTContext() {
578  mRSContext = new RSContext(getPreprocessor(),
579                             getASTContext(),
580                             getTargetInfo(),
581                             &mPragmas,
582                             mTargetAPI,
583                             mVerbose);
584}
585
586bool Slang::IsRSHeaderFile(const char *File) {
587#define RS_HEADER_ENTRY(name)  \
588  if (::strcmp(File, #name "." RS_HEADER_SUFFIX) == 0)  \
589    return true;
590ENUM_RS_HEADER()
591#undef RS_HEADER_ENTRY
592  return false;
593}
594
595bool 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
608bool 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