slang_rs_object_ref_count.cpp revision e639eb5caa2c386b4a60659a4929e8a6141a2cbe
1/*
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
19#include <list>
20
21#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
30namespace slang {
31
32clang::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;
67      } else {
68        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
89void RSObjectRefCount::Scope::AppendToCompoundStatement(
90    clang::ASTContext& C, std::list<clang::Expr*> &ExprList) {
91  // Destructor code will be inserted before any return statement.
92  // Any subsequent statements in the compound statement are then placed
93  // after our new code.
94  // TODO(srhines): This should also handle the case of goto/break/continue.
95  clang::CompoundStmt::body_iterator bI = mCS->body_begin();
96  clang::CompoundStmt::body_iterator bE = mCS->body_end();
97
98  unsigned OldStmtCount = 0;
99  for ( ; bI != bE; bI++) {
100    OldStmtCount++;
101  }
102
103  unsigned NewExprCount = ExprList.size();
104
105  clang::Stmt **StmtList;
106  StmtList = new clang::Stmt*[OldStmtCount+NewExprCount];
107
108  unsigned UpdatedStmtCount = 0;
109  for (bI = mCS->body_begin(); bI != bE; bI++) {
110    if ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass) {
111      break;
112    }
113    StmtList[UpdatedStmtCount++] = *bI;
114  }
115
116  std::list<clang::Expr*>::const_iterator E = ExprList.end();
117  for (std::list<clang::Expr*>::const_iterator I = ExprList.begin(),
118          E = ExprList.end();
119       I != E;
120       I++) {
121    StmtList[UpdatedStmtCount++] = *I;
122  }
123
124  // Pick up anything left over after a return statement
125  for ( ; bI != bE; bI++) {
126    StmtList[UpdatedStmtCount++] = *bI;
127  }
128
129  mCS->setStmts(C, StmtList, UpdatedStmtCount);
130  assert(UpdatedStmtCount == (OldStmtCount + NewExprCount));
131
132  delete [] StmtList;
133
134  return;
135}
136
137void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
138  std::list<clang::Expr*> RSClearObjectCalls;
139  for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
140          E = mRSO.end();
141        I != E;
142        I++) {
143    clang::Expr *E = ClearRSObject(*I);
144    if (E) {
145      RSClearObjectCalls.push_back(E);
146    }
147  }
148  if (RSClearObjectCalls.size() > 0) {
149    clang::ASTContext &C = (*mRSO.begin())->getASTContext();
150    AppendToCompoundStatement(C, RSClearObjectCalls);
151    // TODO(srhines): This should also be extended to append destructors to any
152    // further nested scope (we need another visitor here from within the
153    // current compound statement in case they call return/goto).
154  }
155  return;
156}
157
158clang::Expr *RSObjectRefCount::Scope::ClearRSObject(clang::VarDecl *VD) {
159  clang::ASTContext &C = VD->getASTContext();
160  clang::SourceLocation Loc = VD->getLocation();
161  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
162  RSExportPrimitiveType::DataType DT =
163      RSExportPrimitiveType::GetRSSpecificType(T);
164
165  assert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
166      "Should be RS object");
167
168  // Find the rsClearObject() for VD of RS object type DT
169  clang::FunctionDecl *ClearObjectFD =
170      RSClearObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)];
171  assert((ClearObjectFD != NULL) &&
172      "rsClearObject doesn't cover all RS object types");
173
174  clang::QualType ClearObjectFDType = ClearObjectFD->getType();
175  clang::QualType ClearObjectFDArgType =
176      ClearObjectFD->getParamDecl(0)->getOriginalType();
177
178  // We generate a call to rsClearObject passing &VD as the parameter
179  // (CallExpr 'void'
180  //   (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
181  //     (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
182  //   (UnaryOperator 'rs_font *' prefix '&'
183  //     (DeclRefExpr 'rs_font':'rs_font' Var='[var name]')))
184
185  // Reference expr to target RS object variable
186  clang::DeclRefExpr *RefRSVar =
187      clang::DeclRefExpr::Create(C,
188                                 NULL,
189                                 VD->getQualifierRange(),
190                                 VD,
191                                 Loc,
192                                 T->getCanonicalTypeInternal(),
193                                 NULL);
194
195  // Get address of RSObject in VD
196  clang::Expr *AddrRefRSVar =
197      new(C) clang::UnaryOperator(RefRSVar,
198                                  clang::UO_AddrOf,
199                                  ClearObjectFDArgType,
200                                  Loc);
201
202  clang::Expr *RefRSClearObjectFD =
203      clang::DeclRefExpr::Create(C,
204                                 NULL,
205                                 ClearObjectFD->getQualifierRange(),
206                                 ClearObjectFD,
207                                 ClearObjectFD->getLocation(),
208                                 ClearObjectFDType,
209                                 NULL);
210
211  clang::Expr *RSClearObjectFP =
212      clang::ImplicitCastExpr::Create(C,
213                                      C.getPointerType(ClearObjectFDType),
214                                      clang::CK_FunctionToPointerDecay,
215                                      RefRSClearObjectFD,
216                                      NULL,
217                                      clang::VK_RValue);
218
219  clang::CallExpr *RSClearObjectCall =
220      new(C) clang::CallExpr(C,
221                             RSClearObjectFP,
222                             &AddrRefRSVar,
223                             1,
224                             ClearObjectFD->getCallResultType(),
225                             clang::SourceLocation());
226
227  return RSClearObjectCall;
228}
229
230bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD) {
231  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
232  RSExportPrimitiveType::DataType DT =
233      RSExportPrimitiveType::GetRSSpecificType(T);
234
235  if (DT == RSExportPrimitiveType::DataTypeUnknown)
236    return false;
237
238  if (VD->hasInit()) {
239    // TODO(srhines): Update the reference count of RS object in initializer.
240    // This can potentially be done as part of the assignment pass.
241  } else {
242    clang::Expr *ZeroInitializer =
243        CreateZeroInitializerForRSSpecificType(DT,
244                                               VD->getASTContext(),
245                                               VD->getLocation());
246
247    if (ZeroInitializer) {
248      ZeroInitializer->setType(T->getCanonicalTypeInternal());
249      VD->setInit(ZeroInitializer);
250    }
251  }
252
253  return RSExportPrimitiveType::IsRSObjectType(DT);
254}
255
256clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
257    RSExportPrimitiveType::DataType DT,
258    clang::ASTContext &C,
259    const clang::SourceLocation &Loc) {
260  clang::Expr *Res = NULL;
261  switch (DT) {
262    case RSExportPrimitiveType::DataTypeRSElement:
263    case RSExportPrimitiveType::DataTypeRSType:
264    case RSExportPrimitiveType::DataTypeRSAllocation:
265    case RSExportPrimitiveType::DataTypeRSSampler:
266    case RSExportPrimitiveType::DataTypeRSScript:
267    case RSExportPrimitiveType::DataTypeRSMesh:
268    case RSExportPrimitiveType::DataTypeRSProgramFragment:
269    case RSExportPrimitiveType::DataTypeRSProgramVertex:
270    case RSExportPrimitiveType::DataTypeRSProgramRaster:
271    case RSExportPrimitiveType::DataTypeRSProgramStore:
272    case RSExportPrimitiveType::DataTypeRSFont: {
273      //    (ImplicitCastExpr 'nullptr_t'
274      //      (IntegerLiteral 0)))
275      llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
276      clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
277      clang::Expr *CastToNull =
278          clang::ImplicitCastExpr::Create(C,
279                                          C.NullPtrTy,
280                                          clang::CK_IntegralToPointer,
281                                          Int0,
282                                          NULL,
283                                          clang::VK_RValue);
284
285      Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc);
286      break;
287    }
288    case RSExportPrimitiveType::DataTypeRSMatrix2x2:
289    case RSExportPrimitiveType::DataTypeRSMatrix3x3:
290    case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
291      // RS matrix is not completely an RS object. They hold data by themselves.
292      // (InitListExpr rs_matrix2x2
293      //   (InitListExpr float[4]
294      //     (FloatingLiteral 0)
295      //     (FloatingLiteral 0)
296      //     (FloatingLiteral 0)
297      //     (FloatingLiteral 0)))
298      clang::QualType FloatTy = C.FloatTy;
299      // Constructor sets value to 0.0f by default
300      llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
301      clang::FloatingLiteral *Float0Val =
302          clang::FloatingLiteral::Create(C,
303                                         Val,
304                                         /* isExact = */true,
305                                         FloatTy,
306                                         Loc);
307
308      unsigned N = 0;
309      if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
310        N = 2;
311      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
312        N = 3;
313      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
314        N = 4;
315
316      // Directly allocate 16 elements instead of dynamically allocate N*N
317      clang::Expr *InitVals[16];
318      for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++)
319        InitVals[i] = Float0Val;
320      clang::Expr *InitExpr =
321          new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc);
322      InitExpr->setType(C.getConstantArrayType(FloatTy,
323                                               llvm::APInt(32, 4),
324                                               clang::ArrayType::Normal,
325                                               /* EltTypeQuals = */0));
326
327      Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc);
328      break;
329    }
330    case RSExportPrimitiveType::DataTypeUnknown:
331    case RSExportPrimitiveType::DataTypeFloat16:
332    case RSExportPrimitiveType::DataTypeFloat32:
333    case RSExportPrimitiveType::DataTypeFloat64:
334    case RSExportPrimitiveType::DataTypeSigned8:
335    case RSExportPrimitiveType::DataTypeSigned16:
336    case RSExportPrimitiveType::DataTypeSigned32:
337    case RSExportPrimitiveType::DataTypeSigned64:
338    case RSExportPrimitiveType::DataTypeUnsigned8:
339    case RSExportPrimitiveType::DataTypeUnsigned16:
340    case RSExportPrimitiveType::DataTypeUnsigned32:
341    case RSExportPrimitiveType::DataTypeUnsigned64:
342    case RSExportPrimitiveType::DataTypeBoolean:
343    case RSExportPrimitiveType::DataTypeUnsigned565:
344    case RSExportPrimitiveType::DataTypeUnsigned5551:
345    case RSExportPrimitiveType::DataTypeUnsigned4444:
346    case RSExportPrimitiveType::DataTypeMax: {
347      assert(false && "Not RS object type!");
348    }
349    // No default case will enable compiler detecting the missing cases
350  }
351
352  return Res;
353}
354
355void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
356  for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
357       I != E;
358       I++) {
359    clang::Decl *D = *I;
360    if (D->getKind() == clang::Decl::Var) {
361      clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
362      if (InitializeRSObject(VD))
363        getCurrentScope()->addRSObject(VD);
364    }
365  }
366  return;
367}
368
369void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
370  if (!CS->body_empty()) {
371    // Push a new scope
372    Scope *S = new Scope(CS);
373    mScopeStack.push(S);
374
375    VisitStmt(CS);
376
377    // Destroy the scope
378    // TODO(srhines): Update reference count of the RS object refenced by
379    //                getCurrentScope().
380    assert((getCurrentScope() == S) && "Corrupted scope stack!");
381    S->InsertLocalVarDestructors();
382    mScopeStack.pop();
383    delete S;
384  }
385  return;
386}
387
388void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
389  // TODO(srhines): Update reference count
390  return;
391}
392
393void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
394  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
395       I != E;
396       I++) {
397    if (clang::Stmt *Child = *I) {
398      Visit(Child);
399    }
400  }
401  return;
402}
403
404}  // namespace slang
405