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   const 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   // For diagnostic purposes, we record the order in which we parse
115   // foreach kernels -- which is not necessarily the same order in
116   // which they appear in mExportForEach.
117   unsigned mNextForEachOrdinal;
118 
119   ExportVarList mExportVars;
120   ExportFuncList mExportFuncs;
121   std::map<llvm::StringRef, unsigned> mExportForEachMap;
122   ExportForEachVector mExportForEach;
123   ExportForEachVector::iterator mFirstOldStyleKernel;
124   ExportReduceList mExportReduce;
125   ExportReduceResultTypeSet mExportReduceResultType;
126   ExportTypeMap mExportTypes;
127 
128   clang::QualType mAllocationType;
129   clang::QualType mScriptCallType;
130 
131   std::set<const clang::FunctionDecl *> mUsedByReducePragmaFns;
132 
133   // Populated by markUsedByReducePragma().
134   // Consumed by processReducePragmas().
135   std::vector<clang::VarDecl *> mUsedByReducePragmaDummyVars;
136 
137  public:
138   RSContext(clang::Preprocessor &PP,
139             clang::ASTContext &Ctx,
140             const clang::TargetInfo &Target,
141             PragmaList *Pragmas,
142             unsigned int TargetAPI,
143             bool Verbose);
144 
145   enum CheckName { CheckNameNo, CheckNameYes };
146 
isSyntheticName(const llvm::StringRef Name)147   static bool isSyntheticName(const llvm::StringRef Name) { return Name.startswith(".rs."); }
148 
getPreprocessor()149   inline clang::Preprocessor &getPreprocessor() const { return mPP; }
getASTContext()150   inline clang::ASTContext &getASTContext() const { return mCtx; }
getMangleContext()151   inline clang::MangleContext &getMangleContext() const {
152     return *mMangleCtx;
153   }
getDataLayout()154   inline const llvm::DataLayout &getDataLayout() const { return mDataLayout; }
getLLVMContext()155   inline llvm::LLVMContext &getLLVMContext() const { return mLLVMContext; }
getSourceManager()156   inline const clang::SourceManager *getSourceManager() const {
157     return &mPP.getSourceManager();
158   }
getDiagnostics()159   inline clang::DiagnosticsEngine *getDiagnostics() const {
160     return &mPP.getDiagnostics();
161   }
getTargetAPI()162   inline unsigned int getTargetAPI() const {
163     return mTargetAPI;
164   }
165 
getVerbose()166   inline bool getVerbose() const {
167     return mVerbose;
168   }
is64Bit()169   inline bool is64Bit() const {
170     return mIs64Bit;
171   }
172 
setLicenseNote(const std::string & S)173   inline void setLicenseNote(const std::string &S) {
174     mLicenseNote = new std::string(S);
175   }
getLicenseNote()176   inline const std::string *getLicenseNote() const { return mLicenseNote; }
177 
addExportType(const std::string & S)178   inline void addExportType(const std::string &S) {
179     mNeedExportTypes.insert(S);
180   }
181 
setReflectJavaPackageName(const std::string & S)182   inline void setReflectJavaPackageName(const std::string &S) {
183     mReflectJavaPackageName = S;
184   }
getReflectJavaPackageName()185   inline const std::string &getReflectJavaPackageName() const {
186     return mReflectJavaPackageName;
187   }
188 
setRSPackageName(const std::string & S)189   inline void setRSPackageName(const std::string &S) {
190     mRSPackageName = S;
191   }
192 
getRSPackageName()193   inline const std::string &getRSPackageName() const { return mRSPackageName; }
194 
195   void setAllocationType(const clang::TypeDecl* TD);
getAllocationType()196   inline const clang::QualType& getAllocationType() const {
197     return mAllocationType;
198   }
199 
200   void setScriptCallType(const clang::TypeDecl* TD);
getScriptCallType()201   inline const clang::QualType& getScriptCallType() const {
202     return mScriptCallType;
203   }
204 
205   bool addForEach(const clang::FunctionDecl* FD);
206 
207   bool processExports();
newExportable(RSExportable * E)208   inline void newExportable(RSExportable *E) {
209     if (E != nullptr)
210       mExportables.push_back(E);
211   }
212   typedef ExportableList::iterator exportable_iterator;
exportable_begin()213   exportable_iterator exportable_begin() {
214     return mExportables.begin();
215   }
exportable_end()216   exportable_iterator exportable_end() {
217     return mExportables.end();
218   }
219 
220   typedef ExportVarList::const_iterator const_export_var_iterator;
export_vars_begin()221   const_export_var_iterator export_vars_begin() const {
222     return mExportVars.begin();
223   }
export_vars_end()224   const_export_var_iterator export_vars_end() const {
225     return mExportVars.end();
226   }
hasExportVar()227   inline bool hasExportVar() const {
228     return !mExportVars.empty();
229   }
export_vars_size()230   size_t export_vars_size() const {
231     return mExportVars.size();
232   }
233 
234   typedef ExportFuncList::const_iterator const_export_func_iterator;
export_funcs_begin()235   const_export_func_iterator export_funcs_begin() const {
236     return mExportFuncs.begin();
237   }
export_funcs_end()238   const_export_func_iterator export_funcs_end() const {
239     return mExportFuncs.end();
240   }
hasExportFunc()241   inline bool hasExportFunc() const { return !mExportFuncs.empty(); }
export_funcs_size()242   size_t export_funcs_size() const {
243     return mExportFuncs.size();
244   }
245 
246   typedef ExportForEachVector::const_iterator const_export_foreach_iterator;
export_foreach_begin()247   const_export_foreach_iterator export_foreach_begin() const {
248     return mExportForEach.begin();
249   }
export_foreach_end()250   const_export_foreach_iterator export_foreach_end() const {
251     return mExportForEach.end();
252   }
hasExportForEach()253   inline bool hasExportForEach() const { return !mExportForEach.empty(); }
254   int getForEachSlotNumber(const clang::FunctionDecl* FD);
255 
256   // count up from zero
getNextForEachOrdinal()257   unsigned getNextForEachOrdinal() { return mNextForEachOrdinal++; }
getNumAssignedForEachOrdinals()258   unsigned getNumAssignedForEachOrdinals() const { return mNextForEachOrdinal; }
259 
260   typedef ExportReduceList::const_iterator const_export_reduce_iterator;
export_reduce_begin()261   const_export_reduce_iterator export_reduce_begin() const {
262     return mExportReduce.begin();
263   }
export_reduce_end()264   const_export_reduce_iterator export_reduce_end() const {
265     return mExportReduce.end();
266   }
export_reduce_size()267   size_t export_reduce_size() const {
268     return mExportReduce.size();
269   }
hasExportReduce()270   inline bool hasExportReduce() const { return !mExportReduce.empty(); }
addExportReduce(RSExportReduce * Reduce)271   void addExportReduce(RSExportReduce *Reduce) {
272     mExportReduce.push_back(Reduce);
273   }
274   bool processReducePragmas(Backend *BE);
275   void markUsedByReducePragma(clang::FunctionDecl *FD, CheckName Check);
276 
277   // If the type has already been inserted, has no effect.
insertExportReduceResultType(RSExportType * Type)278   void insertExportReduceResultType(RSExportType *Type) { mExportReduceResultType.insert(Type); }
279 
280   template <class FilterIn, class Compare>
getReduceResultTypes(FilterIn Filt,Compare Comp)281   std::vector<RSExportType *> getReduceResultTypes(FilterIn Filt, Compare Comp) const {
282     std::vector<RSExportType *> Return;
283     std::copy_if(mExportReduceResultType.begin(), mExportReduceResultType.end(), std::back_inserter(Return), Filt);
284     std::sort(Return.begin(), Return.end(), Comp);
285     auto ReturnNewEndIter = std::unique(Return.begin(), Return.end(),
286                                         [Comp](const RSExportType *a, const RSExportType *b) {
287                                           return !Comp(a, b) && !Comp(b, a);
288                                         });
289     Return.erase(ReturnNewEndIter, Return.end());
290     return Return;
291   }
292 
293   typedef ExportTypeMap::iterator export_type_iterator;
294   typedef ExportTypeMap::const_iterator const_export_type_iterator;
export_types_begin()295   export_type_iterator export_types_begin() { return mExportTypes.begin(); }
export_types_end()296   export_type_iterator export_types_end() { return mExportTypes.end(); }
export_types_begin()297   const_export_type_iterator export_types_begin() const {
298     return mExportTypes.begin();
299   }
export_types_end()300   const_export_type_iterator export_types_end() const {
301     return mExportTypes.end();
302   }
hasExportType()303   inline bool hasExportType() const { return !mExportTypes.empty(); }
findExportType(const llvm::StringRef & TypeName)304   export_type_iterator findExportType(const llvm::StringRef &TypeName) {
305     return mExportTypes.find(TypeName);
306   }
findExportType(const llvm::StringRef & TypeName)307   const_export_type_iterator findExportType(const llvm::StringRef &TypeName)
308       const {
309     return mExportTypes.find(TypeName);
310   }
311 
312   // Insert the specified Typename/Type pair into the map. If the key already
313   // exists in the map, return false and ignore the request, otherwise insert it
314   // and return true.
315   bool insertExportType(const llvm::StringRef &TypeName, RSExportType *Type);
316 
getVersion()317   int getVersion() const { return version; }
setVersion(int v)318   void setVersion(int v) {
319     version = v;
320   }
321 
isCompatLib()322   bool isCompatLib() const {
323     // If we are not targeting the actual Android Renderscript classes,
324     // we should reflect code that works with the compatibility library.
325     return (mRSPackageName.compare("android.renderscript") != 0);
326   }
327 
addPragma(const std::string & T,const std::string & V)328   void addPragma(const std::string &T, const std::string &V) {
329     mPragmas->push_back(make_pair(T, V));
330   }
setPrecision(const std::string & P)331   void setPrecision(const std::string &P) { mPrecision = P; }
getPrecision()332   std::string getPrecision() { return mPrecision; }
333 
334   // Report an error or a warning to the user.
335   template <unsigned N>
Report(clang::DiagnosticsEngine::Level Level,const char (& Message)[N])336   clang::DiagnosticBuilder Report(clang::DiagnosticsEngine::Level Level,
337                                              const char (&Message)[N]) const {
338   clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
339   return DiagEngine->Report(DiagEngine->getCustomDiagID(Level, Message));
340   }
341 
342   template <unsigned N>
Report(clang::DiagnosticsEngine::Level Level,const clang::SourceLocation Loc,const char (& Message)[N])343   clang::DiagnosticBuilder Report(clang::DiagnosticsEngine::Level Level,
344                                              const clang::SourceLocation Loc,
345                                              const char (&Message)[N]) const {
346   clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
347   const clang::SourceManager *SM = getSourceManager();
348   return DiagEngine->Report(clang::FullSourceLoc(Loc, *SM),
349                             DiagEngine->getCustomDiagID(Level, Message));
350   }
351 
352   // Utility functions to report errors and warnings to make the calling code
353   // easier to read.
354   template <unsigned N>
ReportError(const char (& Message)[N])355   clang::DiagnosticBuilder ReportError(const char (&Message)[N]) const {
356     return Report<N>(clang::DiagnosticsEngine::Error, Message);
357   }
358 
359   template <unsigned N>
ReportError(const clang::SourceLocation Loc,const char (& Message)[N])360   clang::DiagnosticBuilder ReportError(const clang::SourceLocation Loc,
361                                        const char (&Message)[N]) const {
362     return Report<N>(clang::DiagnosticsEngine::Error, Loc, Message);
363   }
364 
365   template <unsigned N>
ReportWarning(const char (& Message)[N])366   clang::DiagnosticBuilder ReportWarning(const char (&Message)[N]) const {
367     return Report<N>(clang::DiagnosticsEngine::Warning, Message);
368   }
369 
370   template <unsigned N>
ReportWarning(const clang::SourceLocation Loc,const char (& Message)[N])371   clang::DiagnosticBuilder ReportWarning(const clang::SourceLocation Loc,
372                                          const char (&Message)[N]) const {
373     return Report<N>(clang::DiagnosticsEngine::Warning, Loc, Message);
374   }
375 
376   ~RSContext();
377 };
378 
379 }   // namespace slang
380 
381 #endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_CONTEXT_H_  NOLINT
382