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 #ifndef _FRAMEWORKS_COMPILE_SLANG_SLANG_H_  // NOLINT
18 #define _FRAMEWORKS_COMPILE_SLANG_SLANG_H_
19 
20 #include <cstdio>
21 #include <list>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "llvm/ADT/StringMap.h"
27 
28 #include "slang_rs_reflect_utils.h"
29 #include "slang_version.h"
30 
31 // Terrible workaround for TargetOptions.h not using llvm::RefCountedBase!
32 #include "llvm/ADT/IntrusiveRefCntPtr.h"
33 using llvm::RefCountedBase;
34 
35 #include "clang/Basic/LangOptions.h"
36 #include "clang/Basic/TargetOptions.h"
37 #include "clang/Frontend/CodeGenOptions.h"
38 #include "clang/Lex/ModuleLoader.h"
39 
40 #include "llvm/ADT/StringRef.h"
41 
42 #include "llvm/Target/TargetMachine.h"
43 
44 #include "slang_diagnostic_buffer.h"
45 #include "slang_pragma_recorder.h"
46 
47 namespace llvm {
48   class tool_output_file;
49 }
50 
51 namespace clang {
52   class ASTConsumer;
53   class ASTContext;
54   class Backend;
55   class CodeGenOptions;
56   class Diagnostic;
57   class DiagnosticsEngine;
58   class FileManager;
59   class FileSystemOptions;
60   class LangOptions;
61   class Preprocessor;
62   class SourceManager;
63   class TargetInfo;
64 }  // namespace clang
65 
66 namespace slang {
67 
68 class RSCCOptions;
69 class RSContext;
70 class RSExportRecordType;
71 
72 class Slang : public clang::ModuleLoader {
73  public:
74   enum OutputType {
75     OT_Dependency,
76     OT_Assembly,
77     OT_LLVMAssembly,
78     OT_Bitcode,
79     OT_Nothing,
80     OT_Object,
81 
82     OT_Default = OT_Bitcode
83   };
84 
85  private:
86   // Language options (define the language feature for compiler such as C99)
87   clang::LangOptions LangOpts;
88   // Code generation options for the compiler
89   clang::CodeGenOptions CodeGenOpts;
90 
91   // Returns true if this is a Filterscript file.
92   static bool isFilterscript(const char *Filename);
93 
94   // Diagnostics Engine (Producer and Diagnostics Reporter)
95   clang::DiagnosticsEngine *mDiagEngine;
96 
97   // Diagnostics Consumer
98   // NOTE: The ownership is taken by mDiagEngine after creation.
99   DiagnosticBuffer *mDiagClient;
100 
101   // The target being compiled for
102   std::shared_ptr<clang::TargetOptions> mTargetOpts;
103   std::unique_ptr<clang::TargetInfo> mTarget;
104   void createTarget(uint32_t BitWidth);
105 
106   // File manager (for prepocessor doing the job such as header file search)
107   std::unique_ptr<clang::FileManager> mFileMgr;
108   std::unique_ptr<clang::FileSystemOptions> mFileSysOpt;
109   void createFileManager();
110 
111   // Source manager (responsible for the source code handling)
112   std::unique_ptr<clang::SourceManager> mSourceMgr;
113   void createSourceManager();
114 
115   // Preprocessor (source code preprocessor)
116   std::unique_ptr<clang::Preprocessor> mPP;
117   void createPreprocessor();
118 
119   // AST context (the context to hold long-lived AST nodes)
120   std::unique_ptr<clang::ASTContext> mASTContext;
121   void createASTContext();
122 
123   // AST consumer, responsible for code generation
124   std::unique_ptr<clang::ASTConsumer> mBackend;
125 
126   // File names
127   std::string mInputFileName;
128   std::string mOutputFileName;
129   std::string mOutput32FileName;
130 
131   std::string mDepOutputFileName;
132   std::string mDepTargetBCFileName;
133   std::vector<std::string> mAdditionalDepTargets;
134 
135   OutputType mOT;
136 
137   // Output stream
138   std::unique_ptr<llvm::tool_output_file> mOS;
139 
140   // Dependency output stream
141   std::unique_ptr<llvm::tool_output_file> mDOS;
142 
143   std::vector<std::string> mIncludePaths;
144 
145   // Context for Renderscript
146   RSContext *mRSContext;
147 
148   bool mAllowRSPrefix;
149 
150   unsigned int mTargetAPI;
151 
152   bool mVerbose;
153 
154   bool mIsFilterscript;
155 
156   // Collect generated filenames (without the .java) for dependency generation
157   std::vector<std::string> mGeneratedFileNames;
158 
159   PragmaList mPragmas;
160 
161   // FIXME: Should be std::list<RSExportable *> here. But currently we only
162   //        check ODR on record type.
163   //
164   // ReflectedDefinitions maps record type name to a pair:
165   //  <its RSExportRecordType instance,
166   //   the first file contains this record type definition>
167   typedef std::pair<RSExportRecordType*, const char*> ReflectedDefinitionTy;
168   typedef llvm::StringMap<ReflectedDefinitionTy> ReflectedDefinitionListTy;
169   ReflectedDefinitionListTy ReflectedDefinitions;
170 
171   bool generateJavaBitcodeAccessor(const std::string &OutputPathBase,
172                                    const std::string &PackageName,
173                                    const std::string *LicenseNote);
174 
175   // CurInputFile is the pointer to a char array holding the input filename
176   // and is valid before compile() ends.
177   bool checkODR(const char *CurInputFile);
178 
getDiagnostics()179   clang::DiagnosticsEngine &getDiagnostics() { return *mDiagEngine; }
getTargetInfo()180   clang::TargetInfo const &getTargetInfo() const { return *mTarget; }
getFileManager()181   clang::FileManager &getFileManager() { return *mFileMgr; }
getSourceManager()182   clang::SourceManager &getSourceManager() { return *mSourceMgr; }
getPreprocessor()183   clang::Preprocessor &getPreprocessor() { return *mPP; }
getASTContext()184   clang::ASTContext &getASTContext() { return *mASTContext; }
185 
getTargetOptions()186   inline clang::TargetOptions const &getTargetOptions() const
187     { return *mTargetOpts.get(); }
188 
189   void initPreprocessor();
190   void initASTContext();
191 
192   clang::ASTConsumer *createBackend(const clang::CodeGenOptions &CodeGenOpts,
193                                     llvm::raw_ostream *OS,
194                                     OutputType OT);
195 
196  public:
197   static const llvm::StringRef PragmaMetadataName;
198 
199   static void GlobalInitialization();
200 
201   static bool IsRSHeaderFile(const char *File);
202   // FIXME: Determine whether a location is in RS header (i.e., one of the RS
203   //        built-in APIs) should only need its names (we need a "list" of RS
204   //        built-in APIs).
205   static bool IsLocInRSHeaderFile(const clang::SourceLocation &Loc,
206                                   const clang::SourceManager &SourceMgr);
207 
208   Slang(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine,
209         DiagnosticBuffer *DiagClient);
210 
211   virtual ~Slang();
212 
213   bool setInputSource(llvm::StringRef InputFile);
214 
getInputFileName()215   std::string const &getInputFileName() const { return mInputFileName; }
216 
setIncludePaths(const std::vector<std::string> & IncludePaths)217   void setIncludePaths(const std::vector<std::string> &IncludePaths) {
218     mIncludePaths = IncludePaths;
219   }
220 
setOutputType(OutputType OT)221   void setOutputType(OutputType OT) { mOT = OT; }
222 
223   bool setOutput(const char *OutputFile);
224 
225   bool setDepOutput(const char *OutputFile);
226 
setDepTargetBC(const char * TargetBCFile)227   void setDepTargetBC(const char *TargetBCFile) {
228     mDepTargetBCFileName = TargetBCFile;
229   }
230 
setAdditionalDepTargets(std::vector<std::string> const & AdditionalDepTargets)231   void setAdditionalDepTargets(
232       std::vector<std::string> const &AdditionalDepTargets) {
233     mAdditionalDepTargets = AdditionalDepTargets;
234   }
235 
appendGeneratedFileName(std::string const & GeneratedFileName)236   void appendGeneratedFileName(std::string const &GeneratedFileName) {
237     mGeneratedFileNames.push_back(GeneratedFileName);
238   }
239 
240   int generateDepFile();
241 
242   int compile();
243 
getErrorMessage()244   char const *getErrorMessage() { return mDiagClient->str().c_str(); }
245 
246   void setDebugMetadataEmission(bool EmitDebug);
247 
248   void setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel);
249 
250   // Compile bunch of RS files given in the llvm-rs-cc arguments. Return true if
251   // all given input files are successfully compiled without errors.
252   //
253   // @IOFiles - List of pairs of <input file path, output file path>.
254   //
255   // @DepFiles - List of pairs of <output dep. file path, dependent bitcode
256   //             target>. If @OutputDep is true, this parameter must be given
257   //             with the same number of pairs given in @IOFiles.
258   //
259   // @Opts - Selection of options defined from invoking llvm-rs-cc
260   bool
261   compile(const std::list<std::pair<const char *, const char *>> &IOFiles64,
262           const std::list<std::pair<const char *, const char *>> &IOFiles32,
263           const std::list<std::pair<const char *, const char *>> &DepFiles,
264           const RSCCOptions &Opts,
265           clang::DiagnosticOptions &DiagOpts);
266 
267   clang::ModuleLoadResult loadModule(clang::SourceLocation ImportLoc,
268                                      clang::ModuleIdPath Path,
269                                      clang::Module::NameVisibilityKind VK,
270                                      bool IsInclusionDirective) override;
271 
272   void makeModuleVisible(clang::Module *Mod,
273                          clang::Module::NameVisibilityKind Visibility,
274                          clang::SourceLocation ImportLoc,
275                          bool Complain = false) override {}
276 
277   clang::GlobalModuleIndex *
loadGlobalModuleIndex(clang::SourceLocation TriggerLoc)278   loadGlobalModuleIndex(clang::SourceLocation TriggerLoc) override {
279     // We don't support C++ modules for RenderScript.
280     return nullptr;
281   }
282 
lookupMissingImports(llvm::StringRef Name,clang::SourceLocation TriggerLoc)283   bool lookupMissingImports(llvm::StringRef Name,
284                             clang::SourceLocation TriggerLoc) override {
285     // We don't support C++ modules for RenderScript.
286     return false;
287   }
288 };
289 
290 } // namespace slang
291 
292 #endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_H_  NOLINT
293