blob: bba37f6cbf55684c3b02e044646f4cfff3d486e0 [file] [log] [blame]
Stephen Hines4b32ffd2010-11-05 18:47:11 -07001/*
2 * Copyright 2010, 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_object_ref_count.h"
18
Stephen Hinese639eb52010-11-08 19:27:20 -080019#include <list>
20
Stephen Hines4b32ffd2010-11-05 18:47:11 -070021#include "clang/AST/DeclGroup.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/OperationKinds.h"
24#include "clang/AST/Stmt.h"
25#include "clang/AST/StmtVisitor.h"
26
27#include "slang_rs.h"
28#include "slang_rs_export_type.h"
29
Stephen Hinese639eb52010-11-08 19:27:20 -080030namespace slang {
Stephen Hines4b32ffd2010-11-05 18:47:11 -070031
Stephen Hines1bdd4972010-11-08 17:35:08 -080032clang::FunctionDecl *RSObjectRefCount::Scope::
33 RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType -
34 RSExportPrimitiveType::FirstRSObjectType + 1];
35clang::FunctionDecl *RSObjectRefCount::Scope::
36 RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType -
37 RSExportPrimitiveType::FirstRSObjectType + 1];
38
39void RSObjectRefCount::Scope::GetRSRefCountingFunctions(
40 clang::ASTContext &C) {
41 for (unsigned i = 0;
42 i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*));
43 i++) {
44 RSSetObjectFD[i] = NULL;
45 RSClearObjectFD[i] = NULL;
46 }
47
48 clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
49
50 for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
51 E = TUDecl->decls_end(); I != E; I++) {
52 if ((I->getKind() >= clang::Decl::firstFunction) &&
53 (I->getKind() <= clang::Decl::lastFunction)) {
54 clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
55
56 // points to RSSetObjectFD or RSClearObjectFD
57 clang::FunctionDecl **RSObjectFD;
58
59 if (FD->getName() == "rsSetObject") {
60 assert((FD->getNumParams() == 2) &&
61 "Invalid rsSetObject function prototype (# params)");
62 RSObjectFD = RSSetObjectFD;
63 } else if (FD->getName() == "rsClearObject") {
64 assert((FD->getNumParams() == 1) &&
65 "Invalid rsClearObject function prototype (# params)");
66 RSObjectFD = RSClearObjectFD;
Stephen Hinese639eb52010-11-08 19:27:20 -080067 } else {
Stephen Hines1bdd4972010-11-08 17:35:08 -080068 continue;
69 }
70
71 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
72 clang::QualType PVT = PVD->getOriginalType();
73 // The first parameter must be a pointer like rs_allocation*
74 assert(PVT->isPointerType() &&
75 "Invalid rs{Set,Clear}Object function prototype (pointer param)");
76
77 // The rs object type passed to the FD
78 clang::QualType RST = PVT->getPointeeType();
79 RSExportPrimitiveType::DataType DT =
80 RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
81 assert(RSExportPrimitiveType::IsRSObjectType(DT)
82 && "must be RS object type");
83
84 RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD;
85 }
86 }
87}
88
Stephen Hines4464d822010-11-11 16:45:08 -080089namespace {
90
91static void AppendToCompoundStatement(clang::ASTContext& C,
92 clang::CompoundStmt *CS,
93 std::list<clang::Expr*> &ExprList,
94 bool InsertAtEndOfBlock) {
Stephen Hines1bdd4972010-11-08 17:35:08 -080095 // Destructor code will be inserted before any return statement.
96 // Any subsequent statements in the compound statement are then placed
97 // after our new code.
Stephen Hinese639eb52010-11-08 19:27:20 -080098 // TODO(srhines): This should also handle the case of goto/break/continue.
Stephen Hines4464d822010-11-11 16:45:08 -080099
100 clang::CompoundStmt::body_iterator bI = CS->body_begin();
101 clang::CompoundStmt::body_iterator bE = CS->body_end();
Stephen Hines1bdd4972010-11-08 17:35:08 -0800102
103 unsigned OldStmtCount = 0;
Stephen Hines4464d822010-11-11 16:45:08 -0800104 for (bI = CS->body_begin(); bI != bE; bI++) {
Stephen Hines1bdd4972010-11-08 17:35:08 -0800105 OldStmtCount++;
106 }
107
108 unsigned NewExprCount = ExprList.size();
109
110 clang::Stmt **StmtList;
111 StmtList = new clang::Stmt*[OldStmtCount+NewExprCount];
112
113 unsigned UpdatedStmtCount = 0;
Stephen Hines4464d822010-11-11 16:45:08 -0800114 bool FoundReturn = false;
115 for (bI = CS->body_begin(); bI != bE; bI++) {
Stephen Hines1bdd4972010-11-08 17:35:08 -0800116 if ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass) {
Stephen Hines4464d822010-11-11 16:45:08 -0800117 FoundReturn = true;
Stephen Hines1bdd4972010-11-08 17:35:08 -0800118 break;
119 }
120 StmtList[UpdatedStmtCount++] = *bI;
121 }
122
Stephen Hines4464d822010-11-11 16:45:08 -0800123 // Always insert before a return that we found, or if we are told
124 // to insert at the end of the block
125 if (FoundReturn || InsertAtEndOfBlock) {
126 std::list<clang::Expr*>::const_iterator E = ExprList.end();
127 for (std::list<clang::Expr*>::const_iterator I = ExprList.begin(),
128 E = ExprList.end();
129 I != E;
130 I++) {
131 StmtList[UpdatedStmtCount++] = *I;
132 }
Stephen Hines1bdd4972010-11-08 17:35:08 -0800133 }
134
135 // Pick up anything left over after a return statement
136 for ( ; bI != bE; bI++) {
137 StmtList[UpdatedStmtCount++] = *bI;
138 }
139
Stephen Hines4464d822010-11-11 16:45:08 -0800140 CS->setStmts(C, StmtList, UpdatedStmtCount);
Stephen Hines1bdd4972010-11-08 17:35:08 -0800141
142 delete [] StmtList;
143
144 return;
145}
146
Stephen Hines4464d822010-11-11 16:45:08 -0800147// This class visits a compound statement and inserts the ExprList containing
148// destructors in proper locations. This includes inserting them before any
149// return statement in any sub-block, at the end of the logical enclosing
150// scope (compound statement), and/or before any break/continue statement that
151// would resume outside the declared scope. We will not handle the case for
152// goto statements that leave a local scope.
153// TODO(srhines): Make this work properly for break/continue.
154class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
155 private:
156 clang::ASTContext &mC;
157 std::list<clang::Expr*> &mExprList;
158 bool mTopLevel;
159 public:
160 DestructorVisitor(clang::ASTContext &C, std::list<clang::Expr*> &ExprList);
161 void VisitStmt(clang::Stmt *S);
162 void VisitCompoundStmt(clang::CompoundStmt *CS);
163};
164
165DestructorVisitor::DestructorVisitor(clang::ASTContext &C,
166 std::list<clang::Expr*> &ExprList)
167 : mC(C),
168 mExprList(ExprList),
169 mTopLevel(true) {
170 return;
171}
172
173void DestructorVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) {
174 if (!CS->body_empty()) {
175 AppendToCompoundStatement(mC, CS, mExprList, mTopLevel);
176 mTopLevel = false;
177 VisitStmt(CS);
178 }
179 return;
180}
181
182void DestructorVisitor::VisitStmt(clang::Stmt *S) {
183 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
184 I != E;
185 I++) {
186 if (clang::Stmt *Child = *I) {
187 Visit(Child);
188 }
189 }
190 return;
191}
192
193} // namespace
194
Stephen Hines1bdd4972010-11-08 17:35:08 -0800195void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
196 std::list<clang::Expr*> RSClearObjectCalls;
197 for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
198 E = mRSO.end();
199 I != E;
200 I++) {
201 clang::Expr *E = ClearRSObject(*I);
202 if (E) {
203 RSClearObjectCalls.push_back(E);
204 }
205 }
206 if (RSClearObjectCalls.size() > 0) {
Stephen Hines4464d822010-11-11 16:45:08 -0800207 DestructorVisitor DV((*mRSO.begin())->getASTContext(), RSClearObjectCalls);
208 DV.Visit(mCS);
Stephen Hines1bdd4972010-11-08 17:35:08 -0800209 }
210 return;
211}
212
213clang::Expr *RSObjectRefCount::Scope::ClearRSObject(clang::VarDecl *VD) {
214 clang::ASTContext &C = VD->getASTContext();
215 clang::SourceLocation Loc = VD->getLocation();
216 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
217 RSExportPrimitiveType::DataType DT =
218 RSExportPrimitiveType::GetRSSpecificType(T);
219
220 assert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
221 "Should be RS object");
222
223 // Find the rsClearObject() for VD of RS object type DT
224 clang::FunctionDecl *ClearObjectFD =
225 RSClearObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)];
226 assert((ClearObjectFD != NULL) &&
227 "rsClearObject doesn't cover all RS object types");
228
229 clang::QualType ClearObjectFDType = ClearObjectFD->getType();
230 clang::QualType ClearObjectFDArgType =
231 ClearObjectFD->getParamDecl(0)->getOriginalType();
232
233 // We generate a call to rsClearObject passing &VD as the parameter
234 // (CallExpr 'void'
235 // (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
236 // (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
237 // (UnaryOperator 'rs_font *' prefix '&'
238 // (DeclRefExpr 'rs_font':'rs_font' Var='[var name]')))
239
240 // Reference expr to target RS object variable
241 clang::DeclRefExpr *RefRSVar =
242 clang::DeclRefExpr::Create(C,
243 NULL,
244 VD->getQualifierRange(),
245 VD,
246 Loc,
247 T->getCanonicalTypeInternal(),
248 NULL);
249
250 // Get address of RSObject in VD
251 clang::Expr *AddrRefRSVar =
Stephen Hinese639eb52010-11-08 19:27:20 -0800252 new(C) clang::UnaryOperator(RefRSVar,
253 clang::UO_AddrOf,
254 ClearObjectFDArgType,
255 Loc);
Stephen Hines1bdd4972010-11-08 17:35:08 -0800256
257 clang::Expr *RefRSClearObjectFD =
258 clang::DeclRefExpr::Create(C,
259 NULL,
260 ClearObjectFD->getQualifierRange(),
261 ClearObjectFD,
262 ClearObjectFD->getLocation(),
263 ClearObjectFDType,
264 NULL);
265
266 clang::Expr *RSClearObjectFP =
267 clang::ImplicitCastExpr::Create(C,
268 C.getPointerType(ClearObjectFDType),
269 clang::CK_FunctionToPointerDecay,
270 RefRSClearObjectFD,
271 NULL,
272 clang::VK_RValue);
273
274 clang::CallExpr *RSClearObjectCall =
Stephen Hinese639eb52010-11-08 19:27:20 -0800275 new(C) clang::CallExpr(C,
276 RSClearObjectFP,
277 &AddrRefRSVar,
278 1,
279 ClearObjectFD->getCallResultType(),
280 clang::SourceLocation());
Stephen Hines1bdd4972010-11-08 17:35:08 -0800281
282 return RSClearObjectCall;
283}
284
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700285bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD) {
286 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
287 RSExportPrimitiveType::DataType DT =
288 RSExportPrimitiveType::GetRSSpecificType(T);
289
290 if (DT == RSExportPrimitiveType::DataTypeUnknown)
291 return false;
292
293 if (VD->hasInit()) {
Stephen Hinese639eb52010-11-08 19:27:20 -0800294 // TODO(srhines): Update the reference count of RS object in initializer.
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700295 // This can potentially be done as part of the assignment pass.
296 } else {
297 clang::Expr *ZeroInitializer =
298 CreateZeroInitializerForRSSpecificType(DT,
299 VD->getASTContext(),
300 VD->getLocation());
301
302 if (ZeroInitializer) {
303 ZeroInitializer->setType(T->getCanonicalTypeInternal());
304 VD->setInit(ZeroInitializer);
305 }
306 }
307
308 return RSExportPrimitiveType::IsRSObjectType(DT);
309}
310
311clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
312 RSExportPrimitiveType::DataType DT,
313 clang::ASTContext &C,
314 const clang::SourceLocation &Loc) {
315 clang::Expr *Res = NULL;
316 switch (DT) {
317 case RSExportPrimitiveType::DataTypeRSElement:
318 case RSExportPrimitiveType::DataTypeRSType:
319 case RSExportPrimitiveType::DataTypeRSAllocation:
320 case RSExportPrimitiveType::DataTypeRSSampler:
321 case RSExportPrimitiveType::DataTypeRSScript:
322 case RSExportPrimitiveType::DataTypeRSMesh:
323 case RSExportPrimitiveType::DataTypeRSProgramFragment:
324 case RSExportPrimitiveType::DataTypeRSProgramVertex:
325 case RSExportPrimitiveType::DataTypeRSProgramRaster:
326 case RSExportPrimitiveType::DataTypeRSProgramStore:
327 case RSExportPrimitiveType::DataTypeRSFont: {
328 // (ImplicitCastExpr 'nullptr_t'
329 // (IntegerLiteral 0)))
330 llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
331 clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
332 clang::Expr *CastToNull =
333 clang::ImplicitCastExpr::Create(C,
334 C.NullPtrTy,
335 clang::CK_IntegralToPointer,
336 Int0,
337 NULL,
338 clang::VK_RValue);
339
Stephen Hinese639eb52010-11-08 19:27:20 -0800340 Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc);
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700341 break;
342 }
343 case RSExportPrimitiveType::DataTypeRSMatrix2x2:
344 case RSExportPrimitiveType::DataTypeRSMatrix3x3:
345 case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
346 // RS matrix is not completely an RS object. They hold data by themselves.
347 // (InitListExpr rs_matrix2x2
348 // (InitListExpr float[4]
349 // (FloatingLiteral 0)
350 // (FloatingLiteral 0)
351 // (FloatingLiteral 0)
352 // (FloatingLiteral 0)))
353 clang::QualType FloatTy = C.FloatTy;
354 // Constructor sets value to 0.0f by default
355 llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
356 clang::FloatingLiteral *Float0Val =
357 clang::FloatingLiteral::Create(C,
358 Val,
359 /* isExact = */true,
360 FloatTy,
361 Loc);
362
363 unsigned N = 0;
364 if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
365 N = 2;
366 else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
367 N = 3;
368 else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
369 N = 4;
370
371 // Directly allocate 16 elements instead of dynamically allocate N*N
372 clang::Expr *InitVals[16];
373 for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++)
374 InitVals[i] = Float0Val;
375 clang::Expr *InitExpr =
Stephen Hinese639eb52010-11-08 19:27:20 -0800376 new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc);
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700377 InitExpr->setType(C.getConstantArrayType(FloatTy,
378 llvm::APInt(32, 4),
379 clang::ArrayType::Normal,
380 /* EltTypeQuals = */0));
381
Stephen Hinese639eb52010-11-08 19:27:20 -0800382 Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc);
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700383 break;
384 }
385 case RSExportPrimitiveType::DataTypeUnknown:
386 case RSExportPrimitiveType::DataTypeFloat16:
387 case RSExportPrimitiveType::DataTypeFloat32:
388 case RSExportPrimitiveType::DataTypeFloat64:
389 case RSExportPrimitiveType::DataTypeSigned8:
390 case RSExportPrimitiveType::DataTypeSigned16:
391 case RSExportPrimitiveType::DataTypeSigned32:
392 case RSExportPrimitiveType::DataTypeSigned64:
393 case RSExportPrimitiveType::DataTypeUnsigned8:
394 case RSExportPrimitiveType::DataTypeUnsigned16:
395 case RSExportPrimitiveType::DataTypeUnsigned32:
396 case RSExportPrimitiveType::DataTypeUnsigned64:
397 case RSExportPrimitiveType::DataTypeBoolean:
398 case RSExportPrimitiveType::DataTypeUnsigned565:
399 case RSExportPrimitiveType::DataTypeUnsigned5551:
400 case RSExportPrimitiveType::DataTypeUnsigned4444:
401 case RSExportPrimitiveType::DataTypeMax: {
402 assert(false && "Not RS object type!");
403 }
404 // No default case will enable compiler detecting the missing cases
405 }
406
407 return Res;
408}
409
410void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
411 for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
412 I != E;
413 I++) {
414 clang::Decl *D = *I;
415 if (D->getKind() == clang::Decl::Var) {
416 clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
417 if (InitializeRSObject(VD))
418 getCurrentScope()->addRSObject(VD);
419 }
420 }
421 return;
422}
423
424void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
425 if (!CS->body_empty()) {
426 // Push a new scope
427 Scope *S = new Scope(CS);
428 mScopeStack.push(S);
429
430 VisitStmt(CS);
431
432 // Destroy the scope
Stephen Hinese639eb52010-11-08 19:27:20 -0800433 // TODO(srhines): Update reference count of the RS object refenced by
434 // getCurrentScope().
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700435 assert((getCurrentScope() == S) && "Corrupted scope stack!");
Stephen Hines1bdd4972010-11-08 17:35:08 -0800436 S->InsertLocalVarDestructors();
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700437 mScopeStack.pop();
438 delete S;
439 }
440 return;
441}
442
443void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
Stephen Hinese639eb52010-11-08 19:27:20 -0800444 // TODO(srhines): Update reference count
Stephen Hines4b32ffd2010-11-05 18:47:11 -0700445 return;
446}
447
448void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
449 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
450 I != E;
451 I++) {
452 if (clang::Stmt *Child = *I) {
453 Visit(Child);
454 }
455 }
456 return;
457}
458
Stephen Hinese639eb52010-11-08 19:27:20 -0800459} // namespace slang