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,bool Verbose)45 RSContext::RSContext(clang::Preprocessor &PP,
46                      clang::ASTContext &Ctx,
47                      const clang::TargetInfo &Target,
48                      PragmaList *Pragmas,
49                      unsigned int TargetAPI,
50                      bool Verbose)
51     : mPP(PP),
52       mCtx(Ctx),
53       mPragmas(Pragmas),
54       mTargetAPI(TargetAPI),
55       mVerbose(Verbose),
56       mDataLayout(nullptr),
57       mLLVMContext(llvm::getGlobalContext()),
58       mLicenseNote(nullptr),
59       mRSPackageName("android.renderscript"),
60       version(0),
61       mMangleCtx(Ctx.createMangleContext()),
62       mIs64Bit(Target.getPointerWidth(0) == 64) {
63 
64   AddPragmaHandlers(PP, this);
65 
66   // Prepare target data
67   mDataLayout = new llvm::DataLayout(Target.getTargetDescription());
68 }
69 
processExportVar(const clang::VarDecl * VD)70 bool RSContext::processExportVar(const clang::VarDecl *VD) {
71   slangAssert(!VD->getName().empty() && "Variable name should not be empty");
72 
73   // TODO(zonr): some check on variable
74 
75   RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
76   if (!ET)
77     return false;
78 
79   RSExportVar *EV = new RSExportVar(this, VD, ET);
80   if (EV == nullptr)
81     return false;
82   else
83     mExportVars.push_back(EV);
84 
85   return true;
86 }
87 
processExportFunc(const clang::FunctionDecl * FD)88 bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
89   slangAssert(!FD->getName().empty() && "Function name should not be empty");
90 
91   if (!FD->isThisDeclarationADefinition()) {
92     return true;
93   }
94 
95   if (FD->getStorageClass() != clang::SC_None) {
96     fprintf(stderr, "RSContext::processExportFunc : cannot export extern or "
97                     "static function '%s'\n", FD->getName().str().c_str());
98     return false;
99   }
100 
101   if (RSExportForEach::isSpecialRSFunc(mTargetAPI, FD)) {
102     // Do not reflect specialized functions like init, dtor, or graphics root.
103     return RSExportForEach::validateSpecialFuncDecl(mTargetAPI, this, FD);
104   } else if (RSExportForEach::isRSForEachFunc(mTargetAPI, this, FD)) {
105     RSExportForEach *EFE = RSExportForEach::Create(this, FD);
106     if (EFE == nullptr)
107       return false;
108     else
109       mExportForEach.push_back(EFE);
110     return true;
111   }
112 
113   RSExportFunc *EF = RSExportFunc::Create(this, FD);
114   if (EF == nullptr)
115     return false;
116   else
117     mExportFuncs.push_back(EF);
118 
119   return true;
120 }
121 
122 
processExportType(const llvm::StringRef & Name)123 bool RSContext::processExportType(const llvm::StringRef &Name) {
124   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
125 
126   slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level "
127                                    "declaration) is null object");
128 
129   const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
130   if (II == nullptr)
131     // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
132     //             found
133     return false;
134 
135   clang::DeclContext::lookup_result R = TUDecl->lookup(II);
136   RSExportType *ET = nullptr;
137 
138   for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end();
139        I != E;
140        I++) {
141     clang::NamedDecl *const ND = *I;
142     const clang::Type *T = nullptr;
143 
144     switch (ND->getKind()) {
145       case clang::Decl::Typedef: {
146         T = static_cast<const clang::TypedefDecl*>(
147             ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
148         break;
149       }
150       case clang::Decl::Record: {
151         T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
152         break;
153       }
154       default: {
155         // unsupported, skip
156         break;
157       }
158     }
159 
160     if (T != nullptr)
161       ET = RSExportType::Create(this, T);
162   }
163 
164   return (ET != nullptr);
165 }
166 
167 
168 // Possibly re-order ForEach exports (maybe generating a dummy "root" function).
169 // We require "root" to be listed as slot 0 of our exported compute kernels,
170 // so this only needs to be created if we have other non-root kernels.
cleanupForEach()171 void RSContext::cleanupForEach() {
172   bool foundNonRoot = false;
173   ExportForEachList::iterator begin = mExportForEach.begin();
174 
175   for (ExportForEachList::iterator I = begin, E = mExportForEach.end();
176        I != E;
177        I++) {
178     RSExportForEach *EFE = *I;
179     if (!EFE->getName().compare("root")) {
180       if (I == begin) {
181         // Nothing to do, since it is the first function
182         return;
183       }
184 
185       mExportForEach.erase(I);
186       mExportForEach.push_front(EFE);
187       return;
188     } else {
189       foundNonRoot = true;
190     }
191   }
192 
193   // If we found a non-root kernel, but no root() function, we need to add a
194   // dummy version (so that script->script calls of rsForEach don't behave
195   // erratically).
196   if (foundNonRoot) {
197     RSExportForEach *DummyRoot = RSExportForEach::CreateDummyRoot(this);
198     mExportForEach.push_front(DummyRoot);
199   }
200 }
201 
202 
processExport()203 bool RSContext::processExport() {
204   bool valid = true;
205 
206   if (getDiagnostics()->hasErrorOccurred()) {
207     return false;
208   }
209 
210   // Export variable
211   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
212   for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
213            DE = TUDecl->decls_end();
214        DI != DE;
215        DI++) {
216     if (DI->getKind() == clang::Decl::Var) {
217       clang::VarDecl *VD = (clang::VarDecl*) (*DI);
218       if (VD->getFormalLinkage() == clang::ExternalLinkage) {
219         if (!processExportVar(VD)) {
220           valid = false;
221         }
222       }
223     } else if (DI->getKind() == clang::Decl::Function) {
224       // Export functions
225       clang::FunctionDecl *FD = (clang::FunctionDecl*) (*DI);
226       if (FD->getFormalLinkage() == clang::ExternalLinkage) {
227         if (!processExportFunc(FD)) {
228           valid = false;
229         }
230       }
231     }
232   }
233 
234   if (valid) {
235     cleanupForEach();
236   }
237 
238   // Finally, export type forcely set to be exported by user
239   for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
240            EE = mNeedExportTypes.end();
241        EI != EE;
242        EI++) {
243     if (!processExportType(EI->getKey())) {
244       valid = false;
245     }
246   }
247 
248   return valid;
249 }
250 
insertExportType(const llvm::StringRef & TypeName,RSExportType * ET)251 bool RSContext::insertExportType(const llvm::StringRef &TypeName,
252                                  RSExportType *ET) {
253   ExportTypeMap::value_type *NewItem =
254       ExportTypeMap::value_type::Create(TypeName,
255                                         mExportTypes.getAllocator(),
256                                         ET);
257 
258   if (mExportTypes.insert(NewItem)) {
259     return true;
260   } else {
261     free(NewItem);
262     return false;
263   }
264 }
265 
~RSContext()266 RSContext::~RSContext() {
267   delete mLicenseNote;
268   delete mDataLayout;
269   for (ExportableList::iterator I = mExportables.begin(),
270           E = mExportables.end();
271        I != E;
272        I++) {
273     if (!(*I)->isKeep())
274       delete *I;
275   }
276 }
277 
278 }  // namespace slang
279