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