• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "slang_rs_context.h"
18 
19 #include <string>
20 
21 #include "clang/AST/ASTContext.h"
22 #include "clang/AST/Decl.h"
23 #include "clang/AST/DeclBase.h"
24 #include "clang/AST/Mangle.h"
25 #include "clang/AST/Type.h"
26 
27 #include "clang/Basic/Linkage.h"
28 #include "clang/Basic/TargetInfo.h"
29 
30 #include "llvm/IR/LLVMContext.h"
31 #include "llvm/IR/DataLayout.h"
32 
33 #include "slang.h"
34 #include "slang_assert.h"
35 #include "slang_rs_export_foreach.h"
36 #include "slang_rs_export_func.h"
37 #include "slang_rs_export_type.h"
38 #include "slang_rs_export_var.h"
39 #include "slang_rs_exportable.h"
40 #include "slang_rs_pragma_handler.h"
41 #include "slang_rs_reflection.h"
42 
43 namespace slang {
44 
RSContext(clang::Preprocessor & PP,clang::ASTContext & Ctx,const clang::TargetInfo & Target,PragmaList * Pragmas,unsigned int TargetAPI,std::vector<std::string> * GeneratedFileNames)45 RSContext::RSContext(clang::Preprocessor &PP,
46                      clang::ASTContext &Ctx,
47                      const clang::TargetInfo &Target,
48                      PragmaList *Pragmas,
49                      unsigned int TargetAPI,
50                      std::vector<std::string> *GeneratedFileNames)
51     : mPP(PP),
52       mCtx(Ctx),
53       mTarget(Target),
54       mPragmas(Pragmas),
55       mTargetAPI(TargetAPI),
56       mGeneratedFileNames(GeneratedFileNames),
57       mDataLayout(NULL),
58       mLLVMContext(llvm::getGlobalContext()),
59       mLicenseNote(NULL),
60       mRSPackageName("android.renderscript"),
61       version(0),
62       mIsCompatLib(false),
63       mMangleCtx(Ctx.createMangleContext()) {
64   slangAssert(mGeneratedFileNames && "Must supply GeneratedFileNames");
65 
66   // For #pragma rs export_type
67   PP.AddPragmaHandler(
68       "rs", RSPragmaHandler::CreatePragmaExportTypeHandler(this));
69 
70   // For #pragma rs java_package_name
71   PP.AddPragmaHandler(
72       "rs", RSPragmaHandler::CreatePragmaJavaPackageNameHandler(this));
73 
74   // For #pragma rs set_reflect_license
75   PP.AddPragmaHandler(
76       "rs", RSPragmaHandler::CreatePragmaReflectLicenseHandler(this));
77 
78   // For #pragma version
79   PP.AddPragmaHandler(RSPragmaHandler::CreatePragmaVersionHandler(this));
80 
81   // Prepare target data
82   mDataLayout = new llvm::DataLayout(Target.getTargetDescription());
83 
84   return;
85 }
86 
processExportVar(const clang::VarDecl * VD)87 bool RSContext::processExportVar(const clang::VarDecl *VD) {
88   slangAssert(!VD->getName().empty() && "Variable name should not be empty");
89 
90   // TODO(zonr): some check on variable
91 
92   RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
93   if (!ET)
94     return false;
95 
96   RSExportVar *EV = new RSExportVar(this, VD, ET);
97   if (EV == NULL)
98     return false;
99   else
100     mExportVars.push_back(EV);
101 
102   return true;
103 }
104 
processExportFunc(const clang::FunctionDecl * FD)105 bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
106   slangAssert(!FD->getName().empty() && "Function name should not be empty");
107 
108   if (!FD->isThisDeclarationADefinition()) {
109     return true;
110   }
111 
112   if (FD->getStorageClass() != clang::SC_None) {
113     fprintf(stderr, "RSContext::processExportFunc : cannot export extern or "
114                     "static function '%s'\n", FD->getName().str().c_str());
115     return false;
116   }
117 
118   clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
119   if (RSExportForEach::isSpecialRSFunc(mTargetAPI, FD)) {
120     // Do not reflect specialized functions like init, dtor, or graphics root.
121     return RSExportForEach::validateSpecialFuncDecl(mTargetAPI,
122                                                     DiagEngine, FD);
123   } else if (RSExportForEach::isRSForEachFunc(mTargetAPI, DiagEngine, FD)) {
124     RSExportForEach *EFE = RSExportForEach::Create(this, FD);
125     if (EFE == NULL)
126       return false;
127     else
128       mExportForEach.push_back(EFE);
129     return true;
130   }
131 
132   RSExportFunc *EF = RSExportFunc::Create(this, FD);
133   if (EF == NULL)
134     return false;
135   else
136     mExportFuncs.push_back(EF);
137 
138   return true;
139 }
140 
141 
processExportType(const llvm::StringRef & Name)142 bool RSContext::processExportType(const llvm::StringRef &Name) {
143   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
144 
145   slangAssert(TUDecl != NULL && "Translation unit declaration (top-level "
146                                 "declaration) is null object");
147 
148   const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
149   if (II == NULL)
150     // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
151     //             found
152     return false;
153 
154   clang::DeclContext::lookup_const_result R = TUDecl->lookup(II);
155   RSExportType *ET = NULL;
156 
157   for (clang::DeclContext::lookup_const_iterator I = R.begin(), E = R.end();
158        I != E;
159        I++) {
160     clang::NamedDecl *const ND = *I;
161     const clang::Type *T = NULL;
162 
163     switch (ND->getKind()) {
164       case clang::Decl::Typedef: {
165         T = static_cast<const clang::TypedefDecl*>(
166             ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
167         break;
168       }
169       case clang::Decl::Record: {
170         T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
171         break;
172       }
173       default: {
174         // unsupported, skip
175         break;
176       }
177     }
178 
179     if (T != NULL)
180       ET = RSExportType::Create(this, T);
181   }
182 
183   return (ET != NULL);
184 }
185 
186 
187 // Possibly re-order ForEach exports (maybe generating a dummy "root" function).
188 // We require "root" to be listed as slot 0 of our exported compute kernels,
189 // so this only needs to be created if we have other non-root kernels.
cleanupForEach()190 void RSContext::cleanupForEach() {
191   bool foundNonRoot = false;
192   ExportForEachList::iterator begin = mExportForEach.begin();
193 
194   for (ExportForEachList::iterator I = begin, E = mExportForEach.end();
195        I != E;
196        I++) {
197     RSExportForEach *EFE = *I;
198     if (!EFE->getName().compare("root")) {
199       if (I == begin) {
200         // Nothing to do, since it is the first function
201         return;
202       }
203 
204       mExportForEach.erase(I);
205       mExportForEach.push_front(EFE);
206       return;
207     } else {
208       foundNonRoot = true;
209     }
210   }
211 
212   // If we found a non-root kernel, but no root() function, we need to add a
213   // dummy version (so that script->script calls of rsForEach don't behave
214   // erratically).
215   if (foundNonRoot) {
216     RSExportForEach *DummyRoot = RSExportForEach::CreateDummyRoot(this);
217     mExportForEach.push_front(DummyRoot);
218   }
219 }
220 
221 
processExport()222 bool RSContext::processExport() {
223   bool valid = true;
224 
225   if (getDiagnostics()->hasErrorOccurred()) {
226     return false;
227   }
228 
229   // Export variable
230   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
231   for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
232            DE = TUDecl->decls_end();
233        DI != DE;
234        DI++) {
235     if (DI->getKind() == clang::Decl::Var) {
236       clang::VarDecl *VD = (clang::VarDecl*) (*DI);
237       if (VD->getLinkage() == clang::ExternalLinkage) {
238         if (!processExportVar(VD)) {
239           valid = false;
240         }
241       }
242     } else if (DI->getKind() == clang::Decl::Function) {
243       // Export functions
244       clang::FunctionDecl *FD = (clang::FunctionDecl*) (*DI);
245       if (FD->getLinkage() == clang::ExternalLinkage) {
246         if (!processExportFunc(FD)) {
247           valid = false;
248         }
249       }
250     }
251   }
252 
253   if (valid) {
254     cleanupForEach();
255   }
256 
257   // Finally, export type forcely set to be exported by user
258   for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
259            EE = mNeedExportTypes.end();
260        EI != EE;
261        EI++) {
262     if (!processExportType(EI->getKey())) {
263       valid = false;
264     }
265   }
266 
267   return valid;
268 }
269 
insertExportType(const llvm::StringRef & TypeName,RSExportType * ET)270 bool RSContext::insertExportType(const llvm::StringRef &TypeName,
271                                  RSExportType *ET) {
272   ExportTypeMap::value_type *NewItem =
273       ExportTypeMap::value_type::Create(TypeName.begin(),
274                                         TypeName.end(),
275                                         mExportTypes.getAllocator(),
276                                         ET);
277 
278   if (mExportTypes.insert(NewItem)) {
279     return true;
280   } else {
281     free(NewItem);
282     return false;
283   }
284 }
285 
reflectToJava(const std::string & OutputPathBase,const std::string & OutputPackageName,const std::string & RSPackageName,const std::string & InputFileName,const std::string & OutputBCFileName,std::string * RealPackageName)286 bool RSContext::reflectToJava(const std::string &OutputPathBase,
287                               const std::string &OutputPackageName,
288                               const std::string &RSPackageName,
289                               const std::string &InputFileName,
290                               const std::string &OutputBCFileName,
291                               std::string *RealPackageName) {
292   if (RealPackageName != NULL)
293     RealPackageName->clear();
294 
295   const std::string &PackageName =
296       ((OutputPackageName.empty()) ? mReflectJavaPackageName :
297                                      OutputPackageName);
298   slangAssert(!PackageName.empty());
299 
300   // Copy back the really applied package name
301   RealPackageName->assign(PackageName);
302 
303   if (!RSPackageName.empty()) {
304     mRSPackageName = RSPackageName;
305   }
306 
307   // If we are not targeting the actual Android Renderscript classes,
308   // we should reflect code that works with the compatibility library.
309   if (mRSPackageName.compare("android.renderscript") != 0) {
310     mIsCompatLib = true;
311   }
312 
313   RSReflection *R = new RSReflection(this, mGeneratedFileNames);
314   bool ret = R->reflect(OutputPathBase, PackageName, mRSPackageName,
315                         InputFileName, OutputBCFileName);
316   if (!ret)
317     fprintf(stderr, "RSContext::reflectToJava : failed to do reflection "
318                     "(%s)\n", R->getLastError());
319   delete R;
320   return ret;
321 }
322 
~RSContext()323 RSContext::~RSContext() {
324   delete mLicenseNote;
325   delete mDataLayout;
326   for (ExportableList::iterator I = mExportables.begin(),
327           E = mExportables.end();
328        I != E;
329        I++) {
330     if (!(*I)->isKeep())
331       delete *I;
332   }
333 }
334 
335 }  // namespace slang
336