slang_rs_object_ref_count.cpp revision be27482cdeaf08576bc39b72a15d35d13014a636
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/NestedNameSpecifier.h"
24#include "clang/AST/OperationKinds.h"
25#include "clang/AST/Stmt.h"
26#include "clang/AST/StmtVisitor.h"
27
28#include "slang_assert.h"
29#include "slang_rs.h"
30#include "slang_rs_export_type.h"
31
32namespace slang {
33
34clang::FunctionDecl *RSObjectRefCount::
35    RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType -
36                  RSExportPrimitiveType::FirstRSObjectType + 1];
37clang::FunctionDecl *RSObjectRefCount::
38    RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType -
39                    RSExportPrimitiveType::FirstRSObjectType + 1];
40
41void RSObjectRefCount::GetRSRefCountingFunctions(clang::ASTContext &C) {
42  for (unsigned i = 0;
43       i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*));
44       i++) {
45    RSSetObjectFD[i] = NULL;
46    RSClearObjectFD[i] = NULL;
47  }
48
49  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
50
51  for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
52          E = TUDecl->decls_end(); I != E; I++) {
53    if ((I->getKind() >= clang::Decl::firstFunction) &&
54        (I->getKind() <= clang::Decl::lastFunction)) {
55      clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
56
57      // points to RSSetObjectFD or RSClearObjectFD
58      clang::FunctionDecl **RSObjectFD;
59
60      if (FD->getName() == "rsSetObject") {
61        slangAssert((FD->getNumParams() == 2) &&
62                    "Invalid rsSetObject function prototype (# params)");
63        RSObjectFD = RSSetObjectFD;
64      } else if (FD->getName() == "rsClearObject") {
65        slangAssert((FD->getNumParams() == 1) &&
66                    "Invalid rsClearObject function prototype (# params)");
67        RSObjectFD = RSClearObjectFD;
68      } else {
69        continue;
70      }
71
72      const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
73      clang::QualType PVT = PVD->getOriginalType();
74      // The first parameter must be a pointer like rs_allocation*
75      slangAssert(PVT->isPointerType() &&
76          "Invalid rs{Set,Clear}Object function prototype (pointer param)");
77
78      // The rs object type passed to the FD
79      clang::QualType RST = PVT->getPointeeType();
80      RSExportPrimitiveType::DataType DT =
81          RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
82      slangAssert(RSExportPrimitiveType::IsRSObjectType(DT)
83             && "must be RS object type");
84
85      RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD;
86    }
87  }
88}
89
90namespace {
91
92static void AppendToCompoundStatement(clang::ASTContext& C,
93                                      clang::CompoundStmt *CS,
94                                      std::list<clang::Stmt*> &StmtList,
95                                      bool InsertAtEndOfBlock) {
96  // Destructor code will be inserted before any return statement.
97  // Any subsequent statements in the compound statement are then placed
98  // after our new code.
99  // TODO(srhines): This should also handle the case of goto/break/continue.
100
101  clang::CompoundStmt::body_iterator bI = CS->body_begin();
102
103  unsigned OldStmtCount = 0;
104  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
105    OldStmtCount++;
106  }
107
108  unsigned NewStmtCount = StmtList.size();
109
110  clang::Stmt **UpdatedStmtList;
111  UpdatedStmtList = new clang::Stmt*[OldStmtCount+NewStmtCount];
112
113  unsigned UpdatedStmtCount = 0;
114  bool FoundReturn = false;
115  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
116    if ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass) {
117      FoundReturn = true;
118      break;
119    }
120    UpdatedStmtList[UpdatedStmtCount++] = *bI;
121  }
122
123  // 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::Stmt*>::const_iterator I = StmtList.begin();
127    for (std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
128         I != StmtList.end();
129         I++) {
130      UpdatedStmtList[UpdatedStmtCount++] = *I;
131    }
132  }
133
134  // Pick up anything left over after a return statement
135  for ( ; bI != CS->body_end(); bI++) {
136    UpdatedStmtList[UpdatedStmtCount++] = *bI;
137  }
138
139  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
140
141  delete [] UpdatedStmtList;
142
143  return;
144}
145
146static void AppendAfterStmt(clang::ASTContext& C,
147                            clang::CompoundStmt *CS,
148                            clang::Stmt *OldStmt,
149                            clang::Stmt *NewStmt) {
150  slangAssert(CS && OldStmt && NewStmt);
151  clang::CompoundStmt::body_iterator bI = CS->body_begin();
152  unsigned StmtCount = 1;  // Take into account new statement
153  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
154    StmtCount++;
155  }
156
157  clang::Stmt **UpdatedStmtList = new clang::Stmt*[StmtCount];
158
159  unsigned UpdatedStmtCount = 0;
160  unsigned Once = 0;
161  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
162    UpdatedStmtList[UpdatedStmtCount++] = *bI;
163    if (*bI == OldStmt) {
164      Once++;
165      slangAssert(Once == 1);
166      UpdatedStmtList[UpdatedStmtCount++] = NewStmt;
167    }
168  }
169
170  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
171
172  delete [] UpdatedStmtList;
173
174  return;
175}
176
177static void ReplaceInCompoundStmt(clang::ASTContext& C,
178                                  clang::CompoundStmt *CS,
179                                  clang::Stmt* OldStmt,
180                                  clang::Stmt* NewStmt) {
181  clang::CompoundStmt::body_iterator bI = CS->body_begin();
182
183  unsigned StmtCount = 0;
184  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
185    StmtCount++;
186  }
187
188  clang::Stmt **UpdatedStmtList = new clang::Stmt*[StmtCount];
189
190  unsigned UpdatedStmtCount = 0;
191  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
192    if (*bI == OldStmt) {
193      UpdatedStmtList[UpdatedStmtCount++] = NewStmt;
194    } else {
195      UpdatedStmtList[UpdatedStmtCount++] = *bI;
196    }
197  }
198
199  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
200
201  delete [] UpdatedStmtList;
202
203  return;
204}
205
206
207// This class visits a compound statement and inserts the StmtList containing
208// destructors in proper locations. This includes inserting them before any
209// return statement in any sub-block, at the end of the logical enclosing
210// scope (compound statement), and/or before any break/continue statement that
211// would resume outside the declared scope. We will not handle the case for
212// goto statements that leave a local scope.
213// TODO(srhines): Make this work properly for break/continue.
214class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
215 private:
216  clang::ASTContext &mC;
217  std::list<clang::Stmt*> &mStmtList;
218  bool mTopLevel;
219 public:
220  DestructorVisitor(clang::ASTContext &C, std::list<clang::Stmt*> &StmtList);
221  void VisitStmt(clang::Stmt *S);
222  void VisitCompoundStmt(clang::CompoundStmt *CS);
223};
224
225DestructorVisitor::DestructorVisitor(clang::ASTContext &C,
226                                     std::list<clang::Stmt*> &StmtList)
227  : mC(C),
228    mStmtList(StmtList),
229    mTopLevel(true) {
230  return;
231}
232
233void DestructorVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) {
234  if (!CS->body_empty()) {
235    AppendToCompoundStatement(mC, CS, mStmtList, mTopLevel);
236    mTopLevel = false;
237    VisitStmt(CS);
238  }
239  return;
240}
241
242void DestructorVisitor::VisitStmt(clang::Stmt *S) {
243  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
244       I != E;
245       I++) {
246    if (clang::Stmt *Child = *I) {
247      Visit(Child);
248    }
249  }
250  return;
251}
252
253clang::Expr *ClearSingleRSObject(clang::ASTContext &C,
254                                 clang::Expr *RefRSVar,
255                                 clang::SourceLocation Loc) {
256  slangAssert(RefRSVar);
257  const clang::Type *T = RefRSVar->getType().getTypePtr();
258  slangAssert(!T->isArrayType() &&
259              "Should not be destroying arrays with this function");
260
261  clang::FunctionDecl *ClearObjectFD = RSObjectRefCount::GetRSClearObjectFD(T);
262  slangAssert((ClearObjectFD != NULL) &&
263              "rsClearObject doesn't cover all RS object types");
264
265  clang::QualType ClearObjectFDType = ClearObjectFD->getType();
266  clang::QualType ClearObjectFDArgType =
267      ClearObjectFD->getParamDecl(0)->getOriginalType();
268
269  // Example destructor for "rs_font localFont;"
270  //
271  // (CallExpr 'void'
272  //   (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
273  //     (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
274  //   (UnaryOperator 'rs_font *' prefix '&'
275  //     (DeclRefExpr 'rs_font':'rs_font' Var='localFont')))
276
277  // Get address of targeted RS object
278  clang::Expr *AddrRefRSVar =
279      new(C) clang::UnaryOperator(RefRSVar,
280                                  clang::UO_AddrOf,
281                                  ClearObjectFDArgType,
282                                  clang::VK_RValue,
283                                  clang::OK_Ordinary,
284                                  Loc);
285
286  clang::Expr *RefRSClearObjectFD =
287      clang::DeclRefExpr::Create(C,
288                                 clang::NestedNameSpecifierLoc(),
289                                 ClearObjectFD,
290                                 ClearObjectFD->getLocation(),
291                                 ClearObjectFDType,
292                                 clang::VK_RValue,
293                                 NULL);
294
295  clang::Expr *RSClearObjectFP =
296      clang::ImplicitCastExpr::Create(C,
297                                      C.getPointerType(ClearObjectFDType),
298                                      clang::CK_FunctionToPointerDecay,
299                                      RefRSClearObjectFD,
300                                      NULL,
301                                      clang::VK_RValue);
302
303  clang::CallExpr *RSClearObjectCall =
304      new(C) clang::CallExpr(C,
305                             RSClearObjectFP,
306                             &AddrRefRSVar,
307                             1,
308                             ClearObjectFD->getCallResultType(),
309                             clang::VK_RValue,
310                             Loc);
311
312  return RSClearObjectCall;
313}
314
315static int ArrayDim(const clang::Type *T) {
316  if (!T || !T->isArrayType()) {
317    return 0;
318  }
319
320  const clang::ConstantArrayType *CAT =
321    static_cast<const clang::ConstantArrayType *>(T);
322  return static_cast<int>(CAT->getSize().getSExtValue());
323}
324
325static clang::Stmt *ClearStructRSObject(
326    clang::ASTContext &C,
327    clang::DeclContext *DC,
328    clang::Expr *RefRSStruct,
329    clang::SourceLocation Loc);
330
331static clang::Stmt *ClearArrayRSObject(
332    clang::ASTContext &C,
333    clang::DeclContext *DC,
334    clang::Expr *RefRSArr,
335    clang::SourceLocation Loc) {
336  const clang::Type *BaseType = RefRSArr->getType().getTypePtr();
337  slangAssert(BaseType->isArrayType());
338
339  int NumArrayElements = ArrayDim(BaseType);
340  // Actually extract out the base RS object type for use later
341  BaseType = BaseType->getArrayElementTypeNoTypeQual();
342
343  clang::Stmt *StmtArray[2] = {NULL};
344  int StmtCtr = 0;
345
346  if (NumArrayElements <= 0) {
347    return NULL;
348  }
349
350  // Example destructor loop for "rs_font fontArr[10];"
351  //
352  // (CompoundStmt
353  //   (DeclStmt "int rsIntIter")
354  //   (ForStmt
355  //     (BinaryOperator 'int' '='
356  //       (DeclRefExpr 'int' Var='rsIntIter')
357  //       (IntegerLiteral 'int' 0))
358  //     (BinaryOperator 'int' '<'
359  //       (DeclRefExpr 'int' Var='rsIntIter')
360  //       (IntegerLiteral 'int' 10)
361  //     NULL << CondVar >>
362  //     (UnaryOperator 'int' postfix '++'
363  //       (DeclRefExpr 'int' Var='rsIntIter'))
364  //     (CallExpr 'void'
365  //       (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
366  //         (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
367  //       (UnaryOperator 'rs_font *' prefix '&'
368  //         (ArraySubscriptExpr 'rs_font':'rs_font'
369  //           (ImplicitCastExpr 'rs_font *' <ArrayToPointerDecay>
370  //             (DeclRefExpr 'rs_font [10]' Var='fontArr'))
371  //           (DeclRefExpr 'int' Var='rsIntIter')))))))
372
373  // Create helper variable for iterating through elements
374  clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
375  clang::VarDecl *IIVD =
376      clang::VarDecl::Create(C,
377                             DC,
378                             Loc,
379                             &II,
380                             C.IntTy,
381                             C.getTrivialTypeSourceInfo(C.IntTy),
382                             clang::SC_None,
383                             clang::SC_None);
384  clang::Decl *IID = (clang::Decl *)IIVD;
385
386  clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
387  StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
388
389  // Form the actual destructor loop
390  // for (Init; Cond; Inc)
391  //   RSClearObjectCall;
392
393  // Init -> "rsIntIter = 0"
394  clang::DeclRefExpr *RefrsIntIter =
395      clang::DeclRefExpr::Create(C,
396                                 clang::NestedNameSpecifierLoc(),
397                                 IIVD,
398                                 Loc,
399                                 C.IntTy,
400                                 clang::VK_RValue,
401                                 NULL);
402
403  clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
404      llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
405
406  clang::BinaryOperator *Init =
407      new(C) clang::BinaryOperator(RefrsIntIter,
408                                   Int0,
409                                   clang::BO_Assign,
410                                   C.IntTy,
411                                   clang::VK_RValue,
412                                   clang::OK_Ordinary,
413                                   Loc);
414
415  // Cond -> "rsIntIter < NumArrayElements"
416  clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
417      llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
418
419  clang::BinaryOperator *Cond =
420      new(C) clang::BinaryOperator(RefrsIntIter,
421                                   NumArrayElementsExpr,
422                                   clang::BO_LT,
423                                   C.IntTy,
424                                   clang::VK_RValue,
425                                   clang::OK_Ordinary,
426                                   Loc);
427
428  // Inc -> "rsIntIter++"
429  clang::UnaryOperator *Inc =
430      new(C) clang::UnaryOperator(RefrsIntIter,
431                                  clang::UO_PostInc,
432                                  C.IntTy,
433                                  clang::VK_RValue,
434                                  clang::OK_Ordinary,
435                                  Loc);
436
437  // Body -> "rsClearObject(&VD[rsIntIter]);"
438  // Destructor loop operates on individual array elements
439
440  clang::Expr *RefRSArrPtr =
441      clang::ImplicitCastExpr::Create(C,
442          C.getPointerType(BaseType->getCanonicalTypeInternal()),
443          clang::CK_ArrayToPointerDecay,
444          RefRSArr,
445          NULL,
446          clang::VK_RValue);
447
448  clang::Expr *RefRSArrPtrSubscript =
449      new(C) clang::ArraySubscriptExpr(RefRSArrPtr,
450                                       RefrsIntIter,
451                                       BaseType->getCanonicalTypeInternal(),
452                                       clang::VK_RValue,
453                                       clang::OK_Ordinary,
454                                       Loc);
455
456  RSExportPrimitiveType::DataType DT =
457      RSExportPrimitiveType::GetRSSpecificType(BaseType);
458
459  clang::Stmt *RSClearObjectCall = NULL;
460  if (BaseType->isArrayType()) {
461    RSClearObjectCall =
462        ClearArrayRSObject(C, DC, RefRSArrPtrSubscript, Loc);
463  } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
464    RSClearObjectCall =
465        ClearStructRSObject(C, DC, RefRSArrPtrSubscript, Loc);
466  } else {
467    RSClearObjectCall = ClearSingleRSObject(C, RefRSArrPtrSubscript, Loc);
468  }
469
470  clang::ForStmt *DestructorLoop =
471      new(C) clang::ForStmt(C,
472                            Init,
473                            Cond,
474                            NULL,  // no condVar
475                            Inc,
476                            RSClearObjectCall,
477                            Loc,
478                            Loc,
479                            Loc);
480
481  StmtArray[StmtCtr++] = DestructorLoop;
482  slangAssert(StmtCtr == 2);
483
484  clang::CompoundStmt *CS =
485      new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
486
487  return CS;
488}
489
490static unsigned CountRSObjectTypes(const clang::Type *T) {
491  slangAssert(T);
492  unsigned RSObjectCount = 0;
493
494  if (T->isArrayType()) {
495    return CountRSObjectTypes(T->getArrayElementTypeNoTypeQual());
496  }
497
498  RSExportPrimitiveType::DataType DT =
499      RSExportPrimitiveType::GetRSSpecificType(T);
500  if (DT != RSExportPrimitiveType::DataTypeUnknown) {
501    return (RSExportPrimitiveType::IsRSObjectType(DT) ? 1 : 0);
502  }
503
504  if (!T->isStructureType()) {
505    return 0;
506  }
507
508  clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
509  RD = RD->getDefinition();
510  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
511         FE = RD->field_end();
512       FI != FE;
513       FI++) {
514    const clang::FieldDecl *FD = *FI;
515    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
516    if (CountRSObjectTypes(FT)) {
517      // Sub-structs should only count once (as should arrays, etc.)
518      RSObjectCount++;
519    }
520  }
521
522  return RSObjectCount;
523}
524
525static clang::Stmt *ClearStructRSObject(
526    clang::ASTContext &C,
527    clang::DeclContext *DC,
528    clang::Expr *RefRSStruct,
529    clang::SourceLocation Loc) {
530  const clang::Type *BaseType = RefRSStruct->getType().getTypePtr();
531
532  slangAssert(!BaseType->isArrayType());
533
534  RSExportPrimitiveType::DataType DT =
535      RSExportPrimitiveType::GetRSSpecificType(BaseType);
536
537  // Structs should show up as unknown primitive types
538  slangAssert(DT == RSExportPrimitiveType::DataTypeUnknown);
539
540  unsigned FieldsToDestroy = CountRSObjectTypes(BaseType);
541
542  unsigned StmtCount = 0;
543  clang::Stmt **StmtArray = new clang::Stmt*[FieldsToDestroy];
544  for (unsigned i = 0; i < FieldsToDestroy; i++) {
545    StmtArray[i] = NULL;
546  }
547
548  // Populate StmtArray by creating a destructor for each RS object field
549  clang::RecordDecl *RD = BaseType->getAsStructureType()->getDecl();
550  RD = RD->getDefinition();
551  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
552         FE = RD->field_end();
553       FI != FE;
554       FI++) {
555    // We just look through all field declarations to see if we find a
556    // declaration for an RS object type (or an array of one).
557    bool IsArrayType = false;
558    clang::FieldDecl *FD = *FI;
559    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
560    const clang::Type *OrigType = FT;
561    while (FT && FT->isArrayType()) {
562      FT = FT->getArrayElementTypeNoTypeQual();
563      IsArrayType = true;
564    }
565
566    if (RSExportPrimitiveType::IsRSObjectType(FT)) {
567      clang::DeclAccessPair FoundDecl =
568          clang::DeclAccessPair::make(FD, clang::AS_none);
569      clang::MemberExpr *RSObjectMember =
570          clang::MemberExpr::Create(C,
571                                    RefRSStruct,
572                                    false,
573                                    clang::NestedNameSpecifierLoc(),
574                                    FD,
575                                    FoundDecl,
576                                    clang::DeclarationNameInfo(),
577                                    NULL,
578                                    OrigType->getCanonicalTypeInternal(),
579                                    clang::VK_RValue,
580                                    clang::OK_Ordinary);
581
582      slangAssert(StmtCount < FieldsToDestroy);
583
584      if (IsArrayType) {
585        StmtArray[StmtCount++] = ClearArrayRSObject(C,
586                                                    DC,
587                                                    RSObjectMember,
588                                                    Loc);
589      } else {
590        StmtArray[StmtCount++] = ClearSingleRSObject(C,
591                                                     RSObjectMember,
592                                                     Loc);
593      }
594    } else if (FT->isStructureType() && CountRSObjectTypes(FT)) {
595      // In this case, we have a nested struct. We may not end up filling all
596      // of the spaces in StmtArray (sub-structs should handle themselves
597      // with separate compound statements).
598      clang::DeclAccessPair FoundDecl =
599          clang::DeclAccessPair::make(FD, clang::AS_none);
600      clang::MemberExpr *RSObjectMember =
601          clang::MemberExpr::Create(C,
602                                    RefRSStruct,
603                                    false,
604                                    clang::NestedNameSpecifierLoc(),
605                                    FD,
606                                    FoundDecl,
607                                    clang::DeclarationNameInfo(),
608                                    NULL,
609                                    OrigType->getCanonicalTypeInternal(),
610                                    clang::VK_RValue,
611                                    clang::OK_Ordinary);
612
613      if (IsArrayType) {
614        StmtArray[StmtCount++] = ClearArrayRSObject(C,
615                                                    DC,
616                                                    RSObjectMember,
617                                                    Loc);
618      } else {
619        StmtArray[StmtCount++] = ClearStructRSObject(C,
620                                                     DC,
621                                                     RSObjectMember,
622                                                     Loc);
623      }
624    }
625  }
626
627  slangAssert(StmtCount > 0);
628  clang::CompoundStmt *CS =
629      new(C) clang::CompoundStmt(C, StmtArray, StmtCount, Loc, Loc);
630
631  delete [] StmtArray;
632
633  return CS;
634}
635
636static clang::Stmt *CreateSingleRSSetObject(clang::ASTContext &C,
637                                            clang::Diagnostic *Diags,
638                                            clang::Expr *DstExpr,
639                                            clang::Expr *SrcExpr,
640                                            clang::SourceLocation Loc) {
641  const clang::Type *T = DstExpr->getType().getTypePtr();
642  clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(T);
643  slangAssert((SetObjectFD != NULL) &&
644              "rsSetObject doesn't cover all RS object types");
645
646  clang::QualType SetObjectFDType = SetObjectFD->getType();
647  clang::QualType SetObjectFDArgType[2];
648  SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
649  SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
650
651  clang::Expr *RefRSSetObjectFD =
652      clang::DeclRefExpr::Create(C,
653                                 clang::NestedNameSpecifierLoc(),
654                                 SetObjectFD,
655                                 Loc,
656                                 SetObjectFDType,
657                                 clang::VK_RValue,
658                                 NULL);
659
660  clang::Expr *RSSetObjectFP =
661      clang::ImplicitCastExpr::Create(C,
662                                      C.getPointerType(SetObjectFDType),
663                                      clang::CK_FunctionToPointerDecay,
664                                      RefRSSetObjectFD,
665                                      NULL,
666                                      clang::VK_RValue);
667
668  clang::Expr *ArgList[2];
669  ArgList[0] = new(C) clang::UnaryOperator(DstExpr,
670                                           clang::UO_AddrOf,
671                                           SetObjectFDArgType[0],
672                                           clang::VK_RValue,
673                                           clang::OK_Ordinary,
674                                           Loc);
675  ArgList[1] = SrcExpr;
676
677  clang::CallExpr *RSSetObjectCall =
678      new(C) clang::CallExpr(C,
679                             RSSetObjectFP,
680                             ArgList,
681                             2,
682                             SetObjectFD->getCallResultType(),
683                             clang::VK_RValue,
684                             Loc);
685
686  return RSSetObjectCall;
687}
688
689static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
690                                            clang::Diagnostic *Diags,
691                                            clang::Expr *LHS,
692                                            clang::Expr *RHS,
693                                            clang::SourceLocation Loc);
694
695static clang::Stmt *CreateArrayRSSetObject(clang::ASTContext &C,
696                                           clang::Diagnostic *Diags,
697                                           clang::Expr *DstArr,
698                                           clang::Expr *SrcArr,
699                                           clang::SourceLocation Loc) {
700  clang::DeclContext *DC = NULL;
701  const clang::Type *BaseType = DstArr->getType().getTypePtr();
702  slangAssert(BaseType->isArrayType());
703
704  int NumArrayElements = ArrayDim(BaseType);
705  // Actually extract out the base RS object type for use later
706  BaseType = BaseType->getArrayElementTypeNoTypeQual();
707
708  clang::Stmt *StmtArray[2] = {NULL};
709  int StmtCtr = 0;
710
711  if (NumArrayElements <= 0) {
712    return NULL;
713  }
714
715  // Create helper variable for iterating through elements
716  clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
717  clang::VarDecl *IIVD =
718      clang::VarDecl::Create(C,
719                             DC,
720                             Loc,
721                             &II,
722                             C.IntTy,
723                             C.getTrivialTypeSourceInfo(C.IntTy),
724                             clang::SC_None,
725                             clang::SC_None);
726  clang::Decl *IID = (clang::Decl *)IIVD;
727
728  clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
729  StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
730
731  // Form the actual loop
732  // for (Init; Cond; Inc)
733  //   RSSetObjectCall;
734
735  // Init -> "rsIntIter = 0"
736  clang::DeclRefExpr *RefrsIntIter =
737      clang::DeclRefExpr::Create(C,
738                                 clang::NestedNameSpecifierLoc(),
739                                 IIVD,
740                                 Loc,
741                                 C.IntTy,
742                                 clang::VK_RValue,
743                                 NULL);
744
745  clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
746      llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
747
748  clang::BinaryOperator *Init =
749      new(C) clang::BinaryOperator(RefrsIntIter,
750                                   Int0,
751                                   clang::BO_Assign,
752                                   C.IntTy,
753                                   clang::VK_RValue,
754                                   clang::OK_Ordinary,
755                                   Loc);
756
757  // Cond -> "rsIntIter < NumArrayElements"
758  clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
759      llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
760
761  clang::BinaryOperator *Cond =
762      new(C) clang::BinaryOperator(RefrsIntIter,
763                                   NumArrayElementsExpr,
764                                   clang::BO_LT,
765                                   C.IntTy,
766                                   clang::VK_RValue,
767                                   clang::OK_Ordinary,
768                                   Loc);
769
770  // Inc -> "rsIntIter++"
771  clang::UnaryOperator *Inc =
772      new(C) clang::UnaryOperator(RefrsIntIter,
773                                  clang::UO_PostInc,
774                                  C.IntTy,
775                                  clang::VK_RValue,
776                                  clang::OK_Ordinary,
777                                  Loc);
778
779  // Body -> "rsSetObject(&Dst[rsIntIter], Src[rsIntIter]);"
780  // Loop operates on individual array elements
781
782  clang::Expr *DstArrPtr =
783      clang::ImplicitCastExpr::Create(C,
784          C.getPointerType(BaseType->getCanonicalTypeInternal()),
785          clang::CK_ArrayToPointerDecay,
786          DstArr,
787          NULL,
788          clang::VK_RValue);
789
790  clang::Expr *DstArrPtrSubscript =
791      new(C) clang::ArraySubscriptExpr(DstArrPtr,
792                                       RefrsIntIter,
793                                       BaseType->getCanonicalTypeInternal(),
794                                       clang::VK_RValue,
795                                       clang::OK_Ordinary,
796                                       Loc);
797
798  clang::Expr *SrcArrPtr =
799      clang::ImplicitCastExpr::Create(C,
800          C.getPointerType(BaseType->getCanonicalTypeInternal()),
801          clang::CK_ArrayToPointerDecay,
802          SrcArr,
803          NULL,
804          clang::VK_RValue);
805
806  clang::Expr *SrcArrPtrSubscript =
807      new(C) clang::ArraySubscriptExpr(SrcArrPtr,
808                                       RefrsIntIter,
809                                       BaseType->getCanonicalTypeInternal(),
810                                       clang::VK_RValue,
811                                       clang::OK_Ordinary,
812                                       Loc);
813
814  RSExportPrimitiveType::DataType DT =
815      RSExportPrimitiveType::GetRSSpecificType(BaseType);
816
817  clang::Stmt *RSSetObjectCall = NULL;
818  if (BaseType->isArrayType()) {
819    RSSetObjectCall = CreateArrayRSSetObject(C, Diags, DstArrPtrSubscript,
820                                             SrcArrPtrSubscript, Loc);
821  } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
822    RSSetObjectCall = CreateStructRSSetObject(C, Diags, DstArrPtrSubscript,
823                                              SrcArrPtrSubscript, Loc);
824  } else {
825    RSSetObjectCall = CreateSingleRSSetObject(C, Diags, DstArrPtrSubscript,
826                                              SrcArrPtrSubscript, Loc);
827  }
828
829  clang::ForStmt *DestructorLoop =
830      new(C) clang::ForStmt(C,
831                            Init,
832                            Cond,
833                            NULL,  // no condVar
834                            Inc,
835                            RSSetObjectCall,
836                            Loc,
837                            Loc,
838                            Loc);
839
840  StmtArray[StmtCtr++] = DestructorLoop;
841  slangAssert(StmtCtr == 2);
842
843  clang::CompoundStmt *CS =
844      new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
845
846  return CS;
847}
848
849static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
850                                            clang::Diagnostic *Diags,
851                                            clang::Expr *LHS,
852                                            clang::Expr *RHS,
853                                            clang::SourceLocation Loc) {
854  clang::QualType QT = LHS->getType();
855  const clang::Type *T = QT.getTypePtr();
856  slangAssert(T->isStructureType());
857  slangAssert(!RSExportPrimitiveType::IsRSObjectType(T));
858
859  // Keep an extra slot for the original copy (memcpy)
860  unsigned FieldsToSet = CountRSObjectTypes(T) + 1;
861
862  unsigned StmtCount = 0;
863  clang::Stmt **StmtArray = new clang::Stmt*[FieldsToSet];
864  for (unsigned i = 0; i < FieldsToSet; i++) {
865    StmtArray[i] = NULL;
866  }
867
868  clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
869  RD = RD->getDefinition();
870  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
871         FE = RD->field_end();
872       FI != FE;
873       FI++) {
874    bool IsArrayType = false;
875    clang::FieldDecl *FD = *FI;
876    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
877    const clang::Type *OrigType = FT;
878
879    if (!CountRSObjectTypes(FT)) {
880      // Skip to next if we don't have any viable RS object types
881      continue;
882    }
883
884    clang::DeclAccessPair FoundDecl =
885        clang::DeclAccessPair::make(FD, clang::AS_none);
886    clang::MemberExpr *DstMember =
887        clang::MemberExpr::Create(C,
888                                  LHS,
889                                  false,
890                                  clang::NestedNameSpecifierLoc(),
891                                  FD,
892                                  FoundDecl,
893                                  clang::DeclarationNameInfo(),
894                                  NULL,
895                                  OrigType->getCanonicalTypeInternal(),
896                                  clang::VK_RValue,
897                                  clang::OK_Ordinary);
898
899    clang::MemberExpr *SrcMember =
900        clang::MemberExpr::Create(C,
901                                  RHS,
902                                  false,
903                                  clang::NestedNameSpecifierLoc(),
904                                  FD,
905                                  FoundDecl,
906                                  clang::DeclarationNameInfo(),
907                                  NULL,
908                                  OrigType->getCanonicalTypeInternal(),
909                                  clang::VK_RValue,
910                                  clang::OK_Ordinary);
911
912    if (FT->isArrayType()) {
913      FT = FT->getArrayElementTypeNoTypeQual();
914      IsArrayType = true;
915    }
916
917    RSExportPrimitiveType::DataType DT =
918        RSExportPrimitiveType::GetRSSpecificType(FT);
919
920    if (IsArrayType) {
921      Diags->Report(clang::FullSourceLoc(Loc, C.getSourceManager()),
922          Diags->getCustomDiagID(clang::Diagnostic::Error,
923            "Arrays of RS object types within structures cannot be copied"));
924      // TODO(srhines): Support setting arrays of RS objects
925      // StmtArray[StmtCount++] =
926      //    CreateArrayRSSetObject(C, Diags, DstMember, SrcMember, Loc);
927    } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
928      StmtArray[StmtCount++] =
929          CreateStructRSSetObject(C, Diags, DstMember, SrcMember, Loc);
930    } else if (RSExportPrimitiveType::IsRSObjectType(DT)) {
931      StmtArray[StmtCount++] =
932          CreateSingleRSSetObject(C, Diags, DstMember, SrcMember, Loc);
933    } else {
934      slangAssert(false);
935    }
936  }
937
938  slangAssert(StmtCount > 0 && StmtCount < FieldsToSet);
939
940  // We still need to actually do the overall struct copy. For simplicity,
941  // we just do a straight-up assignment (which will still preserve all
942  // the proper RS object reference counts).
943  clang::BinaryOperator *CopyStruct =
944      new(C) clang::BinaryOperator(LHS, RHS, clang::BO_Assign, QT,
945                                   clang::VK_RValue, clang::OK_Ordinary, Loc);
946  StmtArray[StmtCount++] = CopyStruct;
947
948  clang::CompoundStmt *CS =
949      new(C) clang::CompoundStmt(C, StmtArray, StmtCount, Loc, Loc);
950
951  delete [] StmtArray;
952
953  return CS;
954}
955
956}  // namespace
957
958void RSObjectRefCount::Scope::ReplaceRSObjectAssignment(
959    clang::BinaryOperator *AS,
960    clang::Diagnostic *Diags) {
961
962  clang::QualType QT = AS->getType();
963
964  clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
965      RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
966
967  clang::SourceLocation Loc = AS->getExprLoc();
968  clang::Stmt *UpdatedStmt = NULL;
969
970  if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
971    // By definition, this is a struct assignment if we get here
972    UpdatedStmt =
973        CreateStructRSSetObject(C, Diags, AS->getLHS(), AS->getRHS(), Loc);
974  } else {
975    UpdatedStmt =
976        CreateSingleRSSetObject(C, Diags, AS->getLHS(), AS->getRHS(), Loc);
977  }
978
979  ReplaceInCompoundStmt(C, mCS, AS, UpdatedStmt);
980  return;
981}
982
983void RSObjectRefCount::Scope::AppendRSObjectInit(
984    clang::Diagnostic *Diags,
985    clang::VarDecl *VD,
986    clang::DeclStmt *DS,
987    RSExportPrimitiveType::DataType DT,
988    clang::Expr *InitExpr) {
989  slangAssert(VD);
990
991  if (!InitExpr) {
992    return;
993  }
994
995  clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
996      RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
997  clang::SourceLocation Loc = RSObjectRefCount::GetRSSetObjectFD(
998      RSExportPrimitiveType::DataTypeRSFont)->getLocation();
999
1000  if (DT == RSExportPrimitiveType::DataTypeIsStruct) {
1001    // TODO(srhines): Skip struct initialization right now
1002    const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1003    clang::DeclRefExpr *RefRSVar =
1004        clang::DeclRefExpr::Create(C,
1005                                   clang::NestedNameSpecifierLoc(),
1006                                   VD,
1007                                   Loc,
1008                                   T->getCanonicalTypeInternal(),
1009                                   clang::VK_RValue,
1010                                   NULL);
1011
1012    clang::Stmt *RSSetObjectOps =
1013        CreateStructRSSetObject(C, Diags, RefRSVar, InitExpr, Loc);
1014
1015    AppendAfterStmt(C, mCS, DS, RSSetObjectOps);
1016    return;
1017  }
1018
1019  clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
1020  slangAssert((SetObjectFD != NULL) &&
1021              "rsSetObject doesn't cover all RS object types");
1022
1023  clang::QualType SetObjectFDType = SetObjectFD->getType();
1024  clang::QualType SetObjectFDArgType[2];
1025  SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
1026  SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
1027
1028  clang::Expr *RefRSSetObjectFD =
1029      clang::DeclRefExpr::Create(C,
1030                                 clang::NestedNameSpecifierLoc(),
1031                                 SetObjectFD,
1032                                 Loc,
1033                                 SetObjectFDType,
1034                                 clang::VK_RValue,
1035                                 NULL);
1036
1037  clang::Expr *RSSetObjectFP =
1038      clang::ImplicitCastExpr::Create(C,
1039                                      C.getPointerType(SetObjectFDType),
1040                                      clang::CK_FunctionToPointerDecay,
1041                                      RefRSSetObjectFD,
1042                                      NULL,
1043                                      clang::VK_RValue);
1044
1045  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1046  clang::DeclRefExpr *RefRSVar =
1047      clang::DeclRefExpr::Create(C,
1048                                 clang::NestedNameSpecifierLoc(),
1049                                 VD,
1050                                 Loc,
1051                                 T->getCanonicalTypeInternal(),
1052                                 clang::VK_RValue,
1053                                 NULL);
1054
1055  clang::Expr *ArgList[2];
1056  ArgList[0] = new(C) clang::UnaryOperator(RefRSVar,
1057                                           clang::UO_AddrOf,
1058                                           SetObjectFDArgType[0],
1059                                           clang::VK_RValue,
1060                                           clang::OK_Ordinary,
1061                                           Loc);
1062  ArgList[1] = InitExpr;
1063
1064  clang::CallExpr *RSSetObjectCall =
1065      new(C) clang::CallExpr(C,
1066                             RSSetObjectFP,
1067                             ArgList,
1068                             2,
1069                             SetObjectFD->getCallResultType(),
1070                             clang::VK_RValue,
1071                             Loc);
1072
1073  AppendAfterStmt(C, mCS, DS, RSSetObjectCall);
1074
1075  return;
1076}
1077
1078void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
1079  std::list<clang::Stmt*> RSClearObjectCalls;
1080  for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
1081          E = mRSO.end();
1082        I != E;
1083        I++) {
1084    clang::Stmt *S = ClearRSObject(*I);
1085    if (S) {
1086      RSClearObjectCalls.push_back(S);
1087    }
1088  }
1089  if (RSClearObjectCalls.size() > 0) {
1090    DestructorVisitor DV((*mRSO.begin())->getASTContext(), RSClearObjectCalls);
1091    DV.Visit(mCS);
1092  }
1093  return;
1094}
1095
1096clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(clang::VarDecl *VD) {
1097  slangAssert(VD);
1098  clang::ASTContext &C = VD->getASTContext();
1099  clang::DeclContext *DC = VD->getDeclContext();
1100  clang::SourceLocation Loc = VD->getLocation();
1101  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1102
1103  // Reference expr to target RS object variable
1104  clang::DeclRefExpr *RefRSVar =
1105      clang::DeclRefExpr::Create(C,
1106                                 clang::NestedNameSpecifierLoc(),
1107                                 VD,
1108                                 Loc,
1109                                 T->getCanonicalTypeInternal(),
1110                                 clang::VK_RValue,
1111                                 NULL);
1112
1113  if (T->isArrayType()) {
1114    return ClearArrayRSObject(C, DC, RefRSVar, Loc);
1115  }
1116
1117  RSExportPrimitiveType::DataType DT =
1118      RSExportPrimitiveType::GetRSSpecificType(T);
1119
1120  if (DT == RSExportPrimitiveType::DataTypeUnknown ||
1121      DT == RSExportPrimitiveType::DataTypeIsStruct) {
1122    return ClearStructRSObject(C, DC, RefRSVar, Loc);
1123  }
1124
1125  slangAssert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
1126              "Should be RS object");
1127
1128  return ClearSingleRSObject(C, RefRSVar, Loc);
1129}
1130
1131bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD,
1132                                          RSExportPrimitiveType::DataType *DT,
1133                                          clang::Expr **InitExpr) {
1134  slangAssert(VD && DT && InitExpr);
1135  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1136
1137  // Loop through array types to get to base type
1138  while (T && T->isArrayType()) {
1139    T = T->getArrayElementTypeNoTypeQual();
1140  }
1141
1142  bool DataTypeIsStructWithRSObject = false;
1143  *DT = RSExportPrimitiveType::GetRSSpecificType(T);
1144
1145  if (*DT == RSExportPrimitiveType::DataTypeUnknown) {
1146    if (RSExportPrimitiveType::IsStructureTypeWithRSObject(T)) {
1147      *DT = RSExportPrimitiveType::DataTypeIsStruct;
1148      DataTypeIsStructWithRSObject = true;
1149    } else {
1150      return false;
1151    }
1152  }
1153
1154  bool DataTypeIsRSObject = false;
1155  if (DataTypeIsStructWithRSObject) {
1156    DataTypeIsRSObject = true;
1157  } else {
1158    DataTypeIsRSObject = RSExportPrimitiveType::IsRSObjectType(*DT);
1159  }
1160  *InitExpr = VD->getInit();
1161
1162  if (!DataTypeIsRSObject && *InitExpr) {
1163    // If we already have an initializer for a matrix type, we are done.
1164    return DataTypeIsRSObject;
1165  }
1166
1167  clang::Expr *ZeroInitializer =
1168      CreateZeroInitializerForRSSpecificType(*DT,
1169                                             VD->getASTContext(),
1170                                             VD->getLocation());
1171
1172  if (ZeroInitializer) {
1173    ZeroInitializer->setType(T->getCanonicalTypeInternal());
1174    VD->setInit(ZeroInitializer);
1175  }
1176
1177  return DataTypeIsRSObject;
1178}
1179
1180clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
1181    RSExportPrimitiveType::DataType DT,
1182    clang::ASTContext &C,
1183    const clang::SourceLocation &Loc) {
1184  clang::Expr *Res = NULL;
1185  switch (DT) {
1186    case RSExportPrimitiveType::DataTypeIsStruct:
1187    case RSExportPrimitiveType::DataTypeRSElement:
1188    case RSExportPrimitiveType::DataTypeRSType:
1189    case RSExportPrimitiveType::DataTypeRSAllocation:
1190    case RSExportPrimitiveType::DataTypeRSSampler:
1191    case RSExportPrimitiveType::DataTypeRSScript:
1192    case RSExportPrimitiveType::DataTypeRSMesh:
1193    case RSExportPrimitiveType::DataTypeRSProgramFragment:
1194    case RSExportPrimitiveType::DataTypeRSProgramVertex:
1195    case RSExportPrimitiveType::DataTypeRSProgramRaster:
1196    case RSExportPrimitiveType::DataTypeRSProgramStore:
1197    case RSExportPrimitiveType::DataTypeRSFont: {
1198      //    (ImplicitCastExpr 'nullptr_t'
1199      //      (IntegerLiteral 0)))
1200      llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
1201      clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
1202      clang::Expr *CastToNull =
1203          clang::ImplicitCastExpr::Create(C,
1204                                          C.NullPtrTy,
1205                                          clang::CK_IntegralToPointer,
1206                                          Int0,
1207                                          NULL,
1208                                          clang::VK_RValue);
1209
1210      Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc);
1211      break;
1212    }
1213    case RSExportPrimitiveType::DataTypeRSMatrix2x2:
1214    case RSExportPrimitiveType::DataTypeRSMatrix3x3:
1215    case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
1216      // RS matrix is not completely an RS object. They hold data by themselves.
1217      // (InitListExpr rs_matrix2x2
1218      //   (InitListExpr float[4]
1219      //     (FloatingLiteral 0)
1220      //     (FloatingLiteral 0)
1221      //     (FloatingLiteral 0)
1222      //     (FloatingLiteral 0)))
1223      clang::QualType FloatTy = C.FloatTy;
1224      // Constructor sets value to 0.0f by default
1225      llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
1226      clang::FloatingLiteral *Float0Val =
1227          clang::FloatingLiteral::Create(C,
1228                                         Val,
1229                                         /* isExact = */true,
1230                                         FloatTy,
1231                                         Loc);
1232
1233      unsigned N = 0;
1234      if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
1235        N = 2;
1236      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
1237        N = 3;
1238      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
1239        N = 4;
1240
1241      // Directly allocate 16 elements instead of dynamically allocate N*N
1242      clang::Expr *InitVals[16];
1243      for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++)
1244        InitVals[i] = Float0Val;
1245      clang::Expr *InitExpr =
1246          new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc);
1247      InitExpr->setType(C.getConstantArrayType(FloatTy,
1248                                               llvm::APInt(32, 4),
1249                                               clang::ArrayType::Normal,
1250                                               /* EltTypeQuals = */0));
1251
1252      Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc);
1253      break;
1254    }
1255    case RSExportPrimitiveType::DataTypeUnknown:
1256    case RSExportPrimitiveType::DataTypeFloat16:
1257    case RSExportPrimitiveType::DataTypeFloat32:
1258    case RSExportPrimitiveType::DataTypeFloat64:
1259    case RSExportPrimitiveType::DataTypeSigned8:
1260    case RSExportPrimitiveType::DataTypeSigned16:
1261    case RSExportPrimitiveType::DataTypeSigned32:
1262    case RSExportPrimitiveType::DataTypeSigned64:
1263    case RSExportPrimitiveType::DataTypeUnsigned8:
1264    case RSExportPrimitiveType::DataTypeUnsigned16:
1265    case RSExportPrimitiveType::DataTypeUnsigned32:
1266    case RSExportPrimitiveType::DataTypeUnsigned64:
1267    case RSExportPrimitiveType::DataTypeBoolean:
1268    case RSExportPrimitiveType::DataTypeUnsigned565:
1269    case RSExportPrimitiveType::DataTypeUnsigned5551:
1270    case RSExportPrimitiveType::DataTypeUnsigned4444:
1271    case RSExportPrimitiveType::DataTypeMax: {
1272      slangAssert(false && "Not RS object type!");
1273    }
1274    // No default case will enable compiler detecting the missing cases
1275  }
1276
1277  return Res;
1278}
1279
1280void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
1281  for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
1282       I != E;
1283       I++) {
1284    clang::Decl *D = *I;
1285    if (D->getKind() == clang::Decl::Var) {
1286      clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
1287      RSExportPrimitiveType::DataType DT =
1288          RSExportPrimitiveType::DataTypeUnknown;
1289      clang::Expr *InitExpr = NULL;
1290      if (InitializeRSObject(VD, &DT, &InitExpr)) {
1291        getCurrentScope()->addRSObject(VD);
1292        getCurrentScope()->AppendRSObjectInit(mDiags, VD, DS, DT, InitExpr);
1293      }
1294    }
1295  }
1296  return;
1297}
1298
1299void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
1300  if (!CS->body_empty()) {
1301    // Push a new scope
1302    Scope *S = new Scope(CS);
1303    mScopeStack.push(S);
1304
1305    VisitStmt(CS);
1306
1307    // Destroy the scope
1308    slangAssert((getCurrentScope() == S) && "Corrupted scope stack!");
1309    S->InsertLocalVarDestructors();
1310    mScopeStack.pop();
1311    delete S;
1312  }
1313  return;
1314}
1315
1316void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
1317  clang::QualType QT = AS->getType();
1318
1319  if (CountRSObjectTypes(QT.getTypePtr())) {
1320    getCurrentScope()->ReplaceRSObjectAssignment(AS, mDiags);
1321  }
1322
1323  return;
1324}
1325
1326void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
1327  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
1328       I != E;
1329       I++) {
1330    if (clang::Stmt *Child = *I) {
1331      Visit(Child);
1332    }
1333  }
1334  return;
1335}
1336
1337}  // namespace slang
1338