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