1 /*
2  * Copyright 2010-2012, 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_RS_CONTEXT_H_  // NOLINT
18 #define _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_CONTEXT_H_
19 
20 #include <cstdio>
21 #include <list>
22 #include <map>
23 #include <set>
24 #include <string>
25 #include <unordered_set>
26 #include <vector>
27 
28 #include "clang/Lex/Preprocessor.h"
29 #include "clang/AST/Mangle.h"
30 
31 #include "llvm/ADT/StringSet.h"
32 #include "llvm/ADT/StringMap.h"
33 
34 #include "slang_pragma_list.h"
35 
36 namespace llvm {
37   class LLVMContext;
38   class DataLayout;
39 }   // namespace llvm
40 
41 namespace clang {
42   class VarDecl;
43   class ASTContext;
44   class TargetInfo;
45   class FunctionDecl;
46   class QualType;
47   class SourceManager;
48   class TypeDecl;
49   class FunctionDecl;
50 }   // namespace clang
51 
52 namespace slang {
53   class Backend;
54   class RSExportable;
55   class RSExportVar;
56   class RSExportFunc;
57   class RSExportForEach;
58   class RSExportReduce;
59   class RSExportType;
60 
61 class RSContext {
62   typedef llvm::StringSet<> NeedExportVarSet;
63   typedef llvm::StringSet<> NeedExportFuncSet;
64   typedef llvm::StringSet<> NeedExportTypeSet;
65 
66  public:
67   typedef std::list<RSExportable*> ExportableList;
68   typedef std::list<RSExportVar*> ExportVarList;
69   typedef std::list<RSExportFunc*> ExportFuncList;
70   typedef std::vector<RSExportForEach*> ExportForEachVector;
71   typedef std::list<RSExportReduce*> ExportReduceList;
72 
73   // WARNING: Sorted by pointer value, resulting in unpredictable order
74   typedef std::unordered_set<RSExportType*> ExportReduceResultTypeSet;
75 
76   typedef llvm::StringMap<RSExportType*> ExportTypeMap;
77 
78  private:
79   clang::Preprocessor &mPP;
80   clang::ASTContext &mCtx;
81   PragmaList *mPragmas;
82   // Precision specified via pragma, either rs_fp_full or rs_fp_relaxed. If
83   // empty, rs_fp_full is assumed.
84   std::string mPrecision;
85   unsigned int mTargetAPI;
86   bool mVerbose;
87 
88   llvm::DataLayout *mDataLayout;
89   llvm::LLVMContext &mLLVMContext;
90 
91   ExportableList mExportables;
92 
93   NeedExportTypeSet mNeedExportTypes;
94 
95   std::string *mLicenseNote;
96   std::string mReflectJavaPackageName;
97   std::string mReflectJavaPathName;
98 
99   std::string mRSPackageName;
100 
101   int version;
102 
103   std::unique_ptr<clang::MangleContext> mMangleCtx;
104 
105   bool mIs64Bit;
106 
107   bool processExportVar(const clang::VarDecl *VD);
108   bool processExportFunc(const clang::FunctionDecl *FD);
109   bool processExportType(const llvm::StringRef &Name);
110 
111   int getForEachSlotNumber(const clang::StringRef& funcName);
112   unsigned mNextSlot;
113 
114   ExportVarList mExportVars;
115   ExportFuncList mExportFuncs;
116   std::map<llvm::StringRef, unsigned> mExportForEachMap;
117   ExportForEachVector mExportForEach;
118   ExportForEachVector::iterator mFirstOldStyleKernel;
119   ExportReduceList mExportReduce;
120   ExportReduceResultTypeSet mExportReduceResultType;
121   ExportTypeMap mExportTypes;
122 
123   clang::QualType mAllocationType;
124   clang::QualType mScriptCallType;
125 
126   std::set<const clang::FunctionDecl *> mUsedByReducePragmaFns;
127 
128   // Populated by markUsedByReducePragma().
129   // Consumed by processReducePragmas().
130   std::vector<clang::VarDecl *> mUsedByReducePragmaDummyVars;
131 
132  public:
133   RSContext(clang::Preprocessor &PP,
134             clang::ASTContext &Ctx,
135             const clang::TargetInfo &Target,
136             PragmaList *Pragmas,
137             unsigned int TargetAPI,
138             bool Verbose);
139 
140   enum CheckName { CheckNameNo, CheckNameYes };
141 
isSyntheticName(const llvm::StringRef Name)142   static bool isSyntheticName(const llvm::StringRef Name) { return Name.startswith(".rs."); }
143 
getPreprocessor()144   inline clang::Preprocessor &getPreprocessor() const { return mPP; }
getASTContext()145   inline clang::ASTContext &getASTContext() const { return mCtx; }
getMangleContext()146   inline clang::MangleContext &getMangleContext() const {
147     return *mMangleCtx;
148   }
getDataLayout()149   inline const llvm::DataLayout *getDataLayout() const { return mDataLayout; }
getLLVMContext()150   inline llvm::LLVMContext &getLLVMContext() const { return mLLVMContext; }
getSourceManager()151   inline const clang::SourceManager *getSourceManager() const {
152     return &mPP.getSourceManager();
153   }
getDiagnostics()154   inline clang::DiagnosticsEngine *getDiagnostics() const {
155     return &mPP.getDiagnostics();
156   }
getTargetAPI()157   inline unsigned int getTargetAPI() const {
158     return mTargetAPI;
159   }
160 
getVerbose()161   inline bool getVerbose() const {
162     return mVerbose;
163   }
is64Bit()164   inline bool is64Bit() const {
165     return mIs64Bit;
166   }
167 
setLicenseNote(const std::string & S)168   inline void setLicenseNote(const std::string &S) {
169     mLicenseNote = new std::string(S);
170   }
getLicenseNote()171   inline const std::string *getLicenseNote() const { return mLicenseNote; }
172 
addExportType(const std::string & S)173   inline void addExportType(const std::string &S) {
174     mNeedExportTypes.insert(S);
175   }
176 
setReflectJavaPackageName(const std::string & S)177   inline void setReflectJavaPackageName(const std::string &S) {
178     mReflectJavaPackageName = S;
179   }
getReflectJavaPackageName()180   inline const std::string &getReflectJavaPackageName() const {
181     return mReflectJavaPackageName;
182   }
183 
setRSPackageName(const std::string & S)184   inline void setRSPackageName(const std::string &S) {
185     mRSPackageName = S;
186   }
187 
getRSPackageName()188   inline const std::string &getRSPackageName() const { return mRSPackageName; }
189 
190   void setAllocationType(const clang::TypeDecl* TD);
getAllocationType()191   inline const clang::QualType& getAllocationType() const {
192     return mAllocationType;
193   }
194 
195   void setScriptCallType(const clang::TypeDecl* TD);
getScriptCallType()196   inline const clang::QualType& getScriptCallType() const {
197     return mScriptCallType;
198   }
199 
200   bool addForEach(const clang::FunctionDecl* FD);
201   bool processExports();
newExportable(RSExportable * E)202   inline void newExportable(RSExportable *E) {
203     if (E != nullptr)
204       mExportables.push_back(E);
205   }
206   typedef ExportableList::iterator exportable_iterator;
exportable_begin()207   exportable_iterator exportable_begin() {
208     return mExportables.begin();
209   }
exportable_end()210   exportable_iterator exportable_end() {
211     return mExportables.end();
212   }
213 
214   typedef ExportVarList::const_iterator const_export_var_iterator;
export_vars_begin()215   const_export_var_iterator export_vars_begin() const {
216     return mExportVars.begin();
217   }
export_vars_end()218   const_export_var_iterator export_vars_end() const {
219     return mExportVars.end();
220   }
hasExportVar()221   inline bool hasExportVar() const {
222     return !mExportVars.empty();
223   }
224 
225   typedef ExportFuncList::const_iterator const_export_func_iterator;
export_funcs_begin()226   const_export_func_iterator export_funcs_begin() const {
227     return mExportFuncs.begin();
228   }
export_funcs_end()229   const_export_func_iterator export_funcs_end() const {
230     return mExportFuncs.end();
231   }
hasExportFunc()232   inline bool hasExportFunc() const { return !mExportFuncs.empty(); }
233 
234   typedef ExportForEachVector::const_iterator const_export_foreach_iterator;
export_foreach_begin()235   const_export_foreach_iterator export_foreach_begin() const {
236     return mExportForEach.begin();
237   }
export_foreach_end()238   const_export_foreach_iterator export_foreach_end() const {
239     return mExportForEach.end();
240   }
hasExportForEach()241   inline bool hasExportForEach() const { return !mExportForEach.empty(); }
242   int getForEachSlotNumber(const clang::FunctionDecl* FD);
243 
244   typedef ExportReduceList::const_iterator const_export_reduce_iterator;
export_reduce_begin()245   const_export_reduce_iterator export_reduce_begin() const {
246     return mExportReduce.begin();
247   }
export_reduce_end()248   const_export_reduce_iterator export_reduce_end() const {
249     return mExportReduce.end();
250   }
hasExportReduce()251   inline bool hasExportReduce() const { return !mExportReduce.empty(); }
addExportReduce(RSExportReduce * Reduce)252   void addExportReduce(RSExportReduce *Reduce) {
253     mExportReduce.push_back(Reduce);
254   }
255   bool processReducePragmas(Backend *BE);
256   void markUsedByReducePragma(clang::FunctionDecl *FD, CheckName Check);
257 
258   // If the type has already been inserted, has no effect.
insertExportReduceResultType(RSExportType * Type)259   void insertExportReduceResultType(RSExportType *Type) { mExportReduceResultType.insert(Type); }
260 
261   template <class FilterIn, class Compare>
getReduceResultTypes(FilterIn Filt,Compare Comp)262   std::vector<RSExportType *> getReduceResultTypes(FilterIn Filt, Compare Comp) const {
263     std::vector<RSExportType *> Return;
264     std::copy_if(mExportReduceResultType.begin(), mExportReduceResultType.end(), std::back_inserter(Return), Filt);
265     std::sort(Return.begin(), Return.end(), Comp);
266     auto ReturnNewEndIter = std::unique(Return.begin(), Return.end(),
267                                         [Comp](const RSExportType *a, const RSExportType *b) {
268                                           return !Comp(a, b) && !Comp(b, a);
269                                         });
270     Return.erase(ReturnNewEndIter, Return.end());
271     return Return;
272   }
273 
274   typedef ExportTypeMap::iterator export_type_iterator;
275   typedef ExportTypeMap::const_iterator const_export_type_iterator;
export_types_begin()276   export_type_iterator export_types_begin() { return mExportTypes.begin(); }
export_types_end()277   export_type_iterator export_types_end() { return mExportTypes.end(); }
export_types_begin()278   const_export_type_iterator export_types_begin() const {
279     return mExportTypes.begin();
280   }
export_types_end()281   const_export_type_iterator export_types_end() const {
282     return mExportTypes.end();
283   }
hasExportType()284   inline bool hasExportType() const { return !mExportTypes.empty(); }
findExportType(const llvm::StringRef & TypeName)285   export_type_iterator findExportType(const llvm::StringRef &TypeName) {
286     return mExportTypes.find(TypeName);
287   }
findExportType(const llvm::StringRef & TypeName)288   const_export_type_iterator findExportType(const llvm::StringRef &TypeName)
289       const {
290     return mExportTypes.find(TypeName);
291   }
292 
293   // Insert the specified Typename/Type pair into the map. If the key already
294   // exists in the map, return false and ignore the request, otherwise insert it
295   // and return true.
296   bool insertExportType(const llvm::StringRef &TypeName, RSExportType *Type);
297 
getVersion()298   int getVersion() const { return version; }
setVersion(int v)299   void setVersion(int v) {
300     version = v;
301   }
302 
isCompatLib()303   bool isCompatLib() const {
304     // If we are not targeting the actual Android Renderscript classes,
305     // we should reflect code that works with the compatibility library.
306     return (mRSPackageName.compare("android.renderscript") != 0);
307   }
308 
addPragma(const std::string & T,const std::string & V)309   void addPragma(const std::string &T, const std::string &V) {
310     mPragmas->push_back(make_pair(T, V));
311   }
setPrecision(const std::string & P)312   void setPrecision(const std::string &P) { mPrecision = P; }
getPrecision()313   std::string getPrecision() { return mPrecision; }
314 
315   // Report an error or a warning to the user.
316   template <unsigned N>
Report(clang::DiagnosticsEngine::Level Level,const char (& Message)[N])317   clang::DiagnosticBuilder Report(clang::DiagnosticsEngine::Level Level,
318                                              const char (&Message)[N]) {
319   clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
320   return DiagEngine->Report(DiagEngine->getCustomDiagID(Level, Message));
321   }
322 
323   template <unsigned N>
Report(clang::DiagnosticsEngine::Level Level,const clang::SourceLocation Loc,const char (& Message)[N])324   clang::DiagnosticBuilder Report(clang::DiagnosticsEngine::Level Level,
325                                              const clang::SourceLocation Loc,
326                                              const char (&Message)[N]) {
327   clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
328   const clang::SourceManager *SM = getSourceManager();
329   return DiagEngine->Report(clang::FullSourceLoc(Loc, *SM),
330                             DiagEngine->getCustomDiagID(Level, Message));
331   }
332 
333   // Utility functions to report errors and warnings to make the calling code
334   // easier to read.
335   template <unsigned N>
ReportError(const char (& Message)[N])336   clang::DiagnosticBuilder ReportError(const char (&Message)[N]) {
337     return Report<N>(clang::DiagnosticsEngine::Error, Message);
338   }
339 
340   template <unsigned N>
ReportError(const clang::SourceLocation Loc,const char (& Message)[N])341   clang::DiagnosticBuilder ReportError(const clang::SourceLocation Loc,
342                                        const char (&Message)[N]) {
343     return Report<N>(clang::DiagnosticsEngine::Error, Loc, Message);
344   }
345 
346   template <unsigned N>
ReportWarning(const char (& Message)[N])347   clang::DiagnosticBuilder ReportWarning(const char (&Message)[N]) {
348     return Report<N>(clang::DiagnosticsEngine::Warning, Message);
349   }
350 
351   template <unsigned N>
ReportWarning(const clang::SourceLocation Loc,const char (& Message)[N])352   clang::DiagnosticBuilder ReportWarning(const clang::SourceLocation Loc,
353                                          const char (&Message)[N]) {
354     return Report<N>(clang::DiagnosticsEngine::Warning, Loc, Message);
355   }
356 
357   ~RSContext();
358 };
359 
360 }   // namespace slang
361 
362 #endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_CONTEXT_H_  NOLINT
363