• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_export_type.h"
18 
19 #include <list>
20 #include <vector>
21 
22 #include "clang/AST/RecordLayout.h"
23 
24 #include "llvm/ADT/StringExtras.h"
25 
26 #include "llvm/DerivedTypes.h"
27 
28 #include "llvm/Target/TargetData.h"
29 
30 #include "llvm/Type.h"
31 
32 #include "slang_assert.h"
33 #include "slang_rs_context.h"
34 #include "slang_rs_export_element.h"
35 #include "slang_rs_type_spec.h"
36 
37 #define CHECK_PARENT_EQUALITY(ParentClass, E) \
38   if (!ParentClass::equals(E))                \
39     return false;
40 
41 namespace slang {
42 
43 namespace {
44 
45 static const clang::Type *TypeExportableHelper(
46     const clang::Type *T,
47     llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
48     clang::Diagnostic *Diags,
49     const clang::VarDecl *VD,
50     const clang::RecordDecl *TopLevelRecord);
51 
ReportTypeError(clang::Diagnostic * Diags,const clang::VarDecl * VD,const clang::RecordDecl * TopLevelRecord,const char * Message)52 static void ReportTypeError(clang::Diagnostic *Diags,
53                             const clang::VarDecl *VD,
54                             const clang::RecordDecl *TopLevelRecord,
55                             const char *Message) {
56   if (!Diags) {
57     return;
58   }
59 
60   const clang::SourceManager &SM = Diags->getSourceManager();
61 
62   // Attempt to use the type declaration first (if we have one).
63   // Fall back to the variable definition, if we are looking at something
64   // like an array declaration that can't be exported.
65   if (TopLevelRecord) {
66     Diags->Report(clang::FullSourceLoc(TopLevelRecord->getLocation(), SM),
67                   Diags->getCustomDiagID(clang::Diagnostic::Error, Message))
68          << TopLevelRecord->getName();
69   } else if (VD) {
70     Diags->Report(clang::FullSourceLoc(VD->getLocation(), SM),
71                   Diags->getCustomDiagID(clang::Diagnostic::Error, Message))
72          << VD->getName();
73   } else {
74     slangAssert(false && "Variables should be validated before exporting");
75   }
76 
77   return;
78 }
79 
ConstantArrayTypeExportableHelper(const clang::ConstantArrayType * CAT,llvm::SmallPtrSet<const clang::Type *,8> & SPS,clang::Diagnostic * Diags,const clang::VarDecl * VD,const clang::RecordDecl * TopLevelRecord)80 static const clang::Type *ConstantArrayTypeExportableHelper(
81     const clang::ConstantArrayType *CAT,
82     llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
83     clang::Diagnostic *Diags,
84     const clang::VarDecl *VD,
85     const clang::RecordDecl *TopLevelRecord) {
86   // Check element type
87   const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
88   if (ElementType->isArrayType()) {
89     ReportTypeError(Diags, VD, TopLevelRecord,
90         "multidimensional arrays cannot be exported: '%0'");
91     return NULL;
92   } else if (ElementType->isExtVectorType()) {
93     const clang::ExtVectorType *EVT =
94         static_cast<const clang::ExtVectorType*>(ElementType);
95     unsigned numElements = EVT->getNumElements();
96 
97     const clang::Type *BaseElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
98     if (!RSExportPrimitiveType::IsPrimitiveType(BaseElementType)) {
99       ReportTypeError(Diags, VD, TopLevelRecord,
100           "vectors of non-primitive types cannot be exported: '%0'");
101       return NULL;
102     }
103 
104     if (numElements == 3 && CAT->getSize() != 1) {
105       ReportTypeError(Diags, VD, TopLevelRecord,
106           "arrays of width 3 vector types cannot be exported: '%0'");
107       return NULL;
108     }
109   }
110 
111   if (TypeExportableHelper(ElementType, SPS, Diags, VD, TopLevelRecord) == NULL)
112     return NULL;
113   else
114     return CAT;
115 }
116 
TypeExportableHelper(const clang::Type * T,llvm::SmallPtrSet<const clang::Type *,8> & SPS,clang::Diagnostic * Diags,const clang::VarDecl * VD,const clang::RecordDecl * TopLevelRecord)117 static const clang::Type *TypeExportableHelper(
118     const clang::Type *T,
119     llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
120     clang::Diagnostic *Diags,
121     const clang::VarDecl *VD,
122     const clang::RecordDecl *TopLevelRecord) {
123   // Normalize first
124   if ((T = GET_CANONICAL_TYPE(T)) == NULL)
125     return NULL;
126 
127   if (SPS.count(T))
128     return T;
129 
130   switch (T->getTypeClass()) {
131     case clang::Type::Builtin: {
132       const clang::BuiltinType *BT =
133         UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
134 
135       switch (BT->getKind()) {
136 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
137         case builtin_type:
138 #include "RSClangBuiltinEnums.inc"
139           return T;
140         default: {
141           return NULL;
142         }
143       }
144     }
145     case clang::Type::Record: {
146       if (RSExportPrimitiveType::GetRSSpecificType(T) !=
147           RSExportPrimitiveType::DataTypeUnknown)
148         return T;  // RS object type, no further checks are needed
149 
150       // Check internal struct
151       if (T->isUnionType()) {
152         ReportTypeError(Diags, NULL, T->getAsUnionType()->getDecl(),
153             "unions cannot be exported: '%0'");
154         return NULL;
155       } else if (!T->isStructureType()) {
156         slangAssert(false && "Unknown type cannot be exported");
157         return NULL;
158       }
159 
160       clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
161       if (RD != NULL) {
162         RD = RD->getDefinition();
163         if (RD == NULL) {
164           ReportTypeError(Diags, NULL, T->getAsStructureType()->getDecl(),
165               "struct is not defined in this module");
166           return NULL;
167         }
168       }
169 
170       if (!TopLevelRecord) {
171         TopLevelRecord = RD;
172       }
173       if (RD->getName().empty()) {
174         ReportTypeError(Diags, NULL, RD,
175             "anonymous structures cannot be exported");
176         return NULL;
177       }
178 
179       // Fast check
180       if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
181         return NULL;
182 
183       // Insert myself into checking set
184       SPS.insert(T);
185 
186       // Check all element
187       for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
188                FE = RD->field_end();
189            FI != FE;
190            FI++) {
191         const clang::FieldDecl *FD = *FI;
192         const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
193         FT = GET_CANONICAL_TYPE(FT);
194 
195         if (!TypeExportableHelper(FT, SPS, Diags, VD, TopLevelRecord)) {
196           return NULL;
197         }
198 
199         // We don't support bit fields yet
200         //
201         // TODO(zonr/srhines): allow bit fields of size 8, 16, 32
202         if (FD->isBitField()) {
203           if (Diags) {
204             Diags->Report(clang::FullSourceLoc(FD->getLocation(),
205                                                Diags->getSourceManager()),
206                           Diags->getCustomDiagID(clang::Diagnostic::Error,
207                           "bit fields are not able to be exported: '%0.%1'"))
208                 << RD->getName()
209                 << FD->getName();
210           }
211           return NULL;
212         }
213       }
214 
215       return T;
216     }
217     case clang::Type::Pointer: {
218       if (TopLevelRecord) {
219         ReportTypeError(Diags, NULL, TopLevelRecord,
220             "structures containing pointers cannot be exported: '%0'");
221         return NULL;
222       }
223 
224       const clang::PointerType *PT =
225         UNSAFE_CAST_TYPE(const clang::PointerType, T);
226       const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
227 
228       if (PointeeType->getTypeClass() == clang::Type::Pointer)
229         return T;
230       // We don't support pointer with array-type pointee or unsupported pointee
231       // type
232       if (PointeeType->isArrayType() ||
233           (TypeExportableHelper(PointeeType, SPS, Diags, VD,
234                                 TopLevelRecord) == NULL))
235         return NULL;
236       else
237         return T;
238     }
239     case clang::Type::ExtVector: {
240       const clang::ExtVectorType *EVT =
241           UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
242       // Only vector with size 2, 3 and 4 are supported.
243       if (EVT->getNumElements() < 2 || EVT->getNumElements() > 4)
244         return NULL;
245 
246       // Check base element type
247       const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
248 
249       if ((ElementType->getTypeClass() != clang::Type::Builtin) ||
250           (TypeExportableHelper(ElementType, SPS, Diags, VD,
251                                 TopLevelRecord) == NULL))
252         return NULL;
253       else
254         return T;
255     }
256     case clang::Type::ConstantArray: {
257       const clang::ConstantArrayType *CAT =
258           UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T);
259 
260       return ConstantArrayTypeExportableHelper(CAT, SPS, Diags, VD,
261                                                TopLevelRecord);
262     }
263     default: {
264       return NULL;
265     }
266   }
267 }
268 
269 // Return the type that can be used to create RSExportType, will always return
270 // the canonical type
271 // If the Type T is not exportable, this function returns NULL. Diags is
272 // used to generate proper Clang diagnostic messages when a
273 // non-exportable type is detected. TopLevelRecord is used to capture the
274 // highest struct (in the case of a nested hierarchy) for detecting other
275 // types that cannot be exported (mostly pointers within a struct).
TypeExportable(const clang::Type * T,clang::Diagnostic * Diags,const clang::VarDecl * VD)276 static const clang::Type *TypeExportable(const clang::Type *T,
277                                          clang::Diagnostic *Diags,
278                                          const clang::VarDecl *VD) {
279   llvm::SmallPtrSet<const clang::Type*, 8> SPS =
280       llvm::SmallPtrSet<const clang::Type*, 8>();
281 
282   return TypeExportableHelper(T, SPS, Diags, VD, NULL);
283 }
284 
ValidateVarDeclHelper(clang::VarDecl * VD,const clang::Type * & T,llvm::SmallPtrSet<const clang::Type *,8> & SPS,clang::RecordDecl * UnionDecl)285 static bool ValidateVarDeclHelper(
286     clang::VarDecl *VD,
287     const clang::Type *&T,
288     llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
289     clang::RecordDecl *UnionDecl) {
290   if ((T = GET_CANONICAL_TYPE(T)) == NULL)
291     return true;
292 
293   if (SPS.count(T))
294     return true;
295 
296   switch (T->getTypeClass()) {
297     case clang::Type::Record: {
298       if (RSExportPrimitiveType::GetRSSpecificType(T) !=
299           RSExportPrimitiveType::DataTypeUnknown) {
300         if (!UnionDecl) {
301           return true;
302         } else if (RSExportPrimitiveType::IsRSObjectType(T)) {
303           clang::ASTContext &C = VD->getASTContext();
304           ReportTypeError(&C.getDiagnostics(), VD, UnionDecl,
305               "unions containing RS object types are not allowed");
306           return false;
307         }
308       }
309 
310       clang::RecordDecl *RD = NULL;
311 
312       // Check internal struct
313       if (T->isUnionType()) {
314         RD = T->getAsUnionType()->getDecl();
315         UnionDecl = RD;
316       } else if (T->isStructureType()) {
317         RD = T->getAsStructureType()->getDecl();
318       } else {
319         slangAssert(false && "Unknown type cannot be exported");
320         return false;
321       }
322 
323       if (RD != NULL) {
324         RD = RD->getDefinition();
325         if (RD == NULL) {
326           // FIXME
327           return true;
328         }
329       }
330 
331       // Fast check
332       if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
333         return false;
334 
335       // Insert myself into checking set
336       SPS.insert(T);
337 
338       // Check all elements
339       for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
340                FE = RD->field_end();
341            FI != FE;
342            FI++) {
343         const clang::FieldDecl *FD = *FI;
344         const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
345         FT = GET_CANONICAL_TYPE(FT);
346 
347         if (!ValidateVarDeclHelper(VD, FT, SPS, UnionDecl)) {
348           return false;
349         }
350       }
351 
352       return true;
353     }
354 
355     case clang::Type::Builtin: {
356       break;
357     }
358 
359     case clang::Type::Pointer: {
360       const clang::PointerType *PT =
361         UNSAFE_CAST_TYPE(const clang::PointerType, T);
362       const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
363 
364       return ValidateVarDeclHelper(VD, PointeeType, SPS, UnionDecl);
365     }
366 
367     case clang::Type::ExtVector: {
368       const clang::ExtVectorType *EVT =
369           UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
370       const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
371       return ValidateVarDeclHelper(VD, ElementType, SPS, UnionDecl);
372     }
373 
374     case clang::Type::ConstantArray: {
375       const clang::ConstantArrayType *CAT =
376           UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T);
377       const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
378       return ValidateVarDeclHelper(VD, ElementType, SPS, UnionDecl);
379     }
380 
381     default: {
382       break;
383     }
384   }
385 
386   return true;
387 }
388 
389 }  // namespace
390 
391 /****************************** RSExportType ******************************/
NormalizeType(const clang::Type * & T,llvm::StringRef & TypeName,clang::Diagnostic * Diags,const clang::VarDecl * VD)392 bool RSExportType::NormalizeType(const clang::Type *&T,
393                                  llvm::StringRef &TypeName,
394                                  clang::Diagnostic *Diags,
395                                  const clang::VarDecl *VD) {
396   if ((T = TypeExportable(T, Diags, VD)) == NULL) {
397     return false;
398   }
399   // Get type name
400   TypeName = RSExportType::GetTypeName(T);
401   if (TypeName.empty()) {
402     if (Diags) {
403       if (VD) {
404         Diags->Report(clang::FullSourceLoc(VD->getLocation(),
405                                            Diags->getSourceManager()),
406                       Diags->getCustomDiagID(clang::Diagnostic::Error,
407                                              "anonymous types cannot "
408                                              "be exported"));
409       } else {
410         Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
411                                              "anonymous types cannot "
412                                              "be exported"));
413       }
414     }
415     return false;
416   }
417 
418   return true;
419 }
420 
ValidateVarDecl(clang::VarDecl * VD)421 bool RSExportType::ValidateVarDecl(clang::VarDecl *VD) {
422   const clang::Type *T = VD->getType().getTypePtr();
423   llvm::SmallPtrSet<const clang::Type*, 8> SPS =
424       llvm::SmallPtrSet<const clang::Type*, 8>();
425 
426   return ValidateVarDeclHelper(VD, T, SPS, NULL);
427 }
428 
429 const clang::Type
GetTypeOfDecl(const clang::DeclaratorDecl * DD)430 *RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) {
431   if (DD) {
432     clang::QualType T;
433     if (DD->getTypeSourceInfo())
434       T = DD->getTypeSourceInfo()->getType();
435     else
436       T = DD->getType();
437 
438     if (T.isNull())
439       return NULL;
440     else
441       return T.getTypePtr();
442   }
443   return NULL;
444 }
445 
GetTypeName(const clang::Type * T)446 llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) {
447   T = GET_CANONICAL_TYPE(T);
448   if (T == NULL)
449     return llvm::StringRef();
450 
451   switch (T->getTypeClass()) {
452     case clang::Type::Builtin: {
453       const clang::BuiltinType *BT =
454         UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
455 
456       switch (BT->getKind()) {
457 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
458         case builtin_type:                                    \
459           return cname;                                       \
460         break;
461 #include "RSClangBuiltinEnums.inc"
462         default: {
463           slangAssert(false && "Unknown data type of the builtin");
464           break;
465         }
466       }
467       break;
468     }
469     case clang::Type::Record: {
470       clang::RecordDecl *RD;
471       if (T->isStructureType()) {
472         RD = T->getAsStructureType()->getDecl();
473       } else {
474         break;
475       }
476 
477       llvm::StringRef Name = RD->getName();
478       if (Name.empty()) {
479         if (RD->getTypedefNameForAnonDecl() != NULL) {
480           Name = RD->getTypedefNameForAnonDecl()->getName();
481         }
482 
483         if (Name.empty()) {
484           // Try to find a name from redeclaration (i.e. typedef)
485           for (clang::TagDecl::redecl_iterator RI = RD->redecls_begin(),
486                    RE = RD->redecls_end();
487                RI != RE;
488                RI++) {
489             slangAssert(*RI != NULL && "cannot be NULL object");
490 
491             Name = (*RI)->getName();
492             if (!Name.empty())
493               break;
494           }
495         }
496       }
497       return Name;
498     }
499     case clang::Type::Pointer: {
500       // "*" plus pointee name
501       const clang::Type *PT = GET_POINTEE_TYPE(T);
502       llvm::StringRef PointeeName;
503       if (NormalizeType(PT, PointeeName, NULL, NULL)) {
504         char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ];
505         Name[0] = '*';
506         memcpy(Name + 1, PointeeName.data(), PointeeName.size());
507         Name[PointeeName.size() + 1] = '\0';
508         return Name;
509       }
510       break;
511     }
512     case clang::Type::ExtVector: {
513       const clang::ExtVectorType *EVT =
514           UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
515       return RSExportVectorType::GetTypeName(EVT);
516       break;
517     }
518     case clang::Type::ConstantArray : {
519       // Construct name for a constant array is too complicated.
520       return DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE;
521     }
522     default: {
523       break;
524     }
525   }
526 
527   return llvm::StringRef();
528 }
529 
530 
Create(RSContext * Context,const clang::Type * T,const llvm::StringRef & TypeName)531 RSExportType *RSExportType::Create(RSContext *Context,
532                                    const clang::Type *T,
533                                    const llvm::StringRef &TypeName) {
534   // Lookup the context to see whether the type was processed before.
535   // Newly created RSExportType will insert into context
536   // in RSExportType::RSExportType()
537   RSContext::export_type_iterator ETI = Context->findExportType(TypeName);
538 
539   if (ETI != Context->export_types_end())
540     return ETI->second;
541 
542   RSExportType *ET = NULL;
543   switch (T->getTypeClass()) {
544     case clang::Type::Record: {
545       RSExportPrimitiveType::DataType dt =
546           RSExportPrimitiveType::GetRSSpecificType(TypeName);
547       switch (dt) {
548         case RSExportPrimitiveType::DataTypeUnknown: {
549           // User-defined types
550           ET = RSExportRecordType::Create(Context,
551                                           T->getAsStructureType(),
552                                           TypeName);
553           break;
554         }
555         case RSExportPrimitiveType::DataTypeRSMatrix2x2: {
556           // 2 x 2 Matrix type
557           ET = RSExportMatrixType::Create(Context,
558                                           T->getAsStructureType(),
559                                           TypeName,
560                                           2);
561           break;
562         }
563         case RSExportPrimitiveType::DataTypeRSMatrix3x3: {
564           // 3 x 3 Matrix type
565           ET = RSExportMatrixType::Create(Context,
566                                           T->getAsStructureType(),
567                                           TypeName,
568                                           3);
569           break;
570         }
571         case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
572           // 4 x 4 Matrix type
573           ET = RSExportMatrixType::Create(Context,
574                                           T->getAsStructureType(),
575                                           TypeName,
576                                           4);
577           break;
578         }
579         default: {
580           // Others are primitive types
581           ET = RSExportPrimitiveType::Create(Context, T, TypeName);
582           break;
583         }
584       }
585       break;
586     }
587     case clang::Type::Builtin: {
588       ET = RSExportPrimitiveType::Create(Context, T, TypeName);
589       break;
590     }
591     case clang::Type::Pointer: {
592       ET = RSExportPointerType::Create(Context,
593                UNSAFE_CAST_TYPE(const clang::PointerType, T), TypeName);
594       // FIXME: free the name (allocated in RSExportType::GetTypeName)
595       delete [] TypeName.data();
596       break;
597     }
598     case clang::Type::ExtVector: {
599       ET = RSExportVectorType::Create(Context,
600                UNSAFE_CAST_TYPE(const clang::ExtVectorType, T), TypeName);
601       break;
602     }
603     case clang::Type::ConstantArray: {
604       ET = RSExportConstantArrayType::Create(
605               Context,
606               UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T));
607       break;
608     }
609     default: {
610       clang::Diagnostic *Diags = Context->getDiagnostics();
611       Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
612                         "unknown type cannot be exported: '%0'"))
613           << T->getTypeClassName();
614       break;
615     }
616   }
617 
618   return ET;
619 }
620 
Create(RSContext * Context,const clang::Type * T)621 RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) {
622   llvm::StringRef TypeName;
623   if (NormalizeType(T, TypeName, Context->getDiagnostics(), NULL))
624     return Create(Context, T, TypeName);
625   else
626     return NULL;
627 }
628 
CreateFromDecl(RSContext * Context,const clang::VarDecl * VD)629 RSExportType *RSExportType::CreateFromDecl(RSContext *Context,
630                                            const clang::VarDecl *VD) {
631   return RSExportType::Create(Context, GetTypeOfDecl(VD));
632 }
633 
GetTypeStoreSize(const RSExportType * ET)634 size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) {
635   return ET->getRSContext()->getTargetData()->getTypeStoreSize(
636       ET->getLLVMType());
637 }
638 
GetTypeAllocSize(const RSExportType * ET)639 size_t RSExportType::GetTypeAllocSize(const RSExportType *ET) {
640   if (ET->getClass() == RSExportType::ExportClassRecord)
641     return static_cast<const RSExportRecordType*>(ET)->getAllocSize();
642   else
643     return ET->getRSContext()->getTargetData()->getTypeAllocSize(
644         ET->getLLVMType());
645 }
646 
RSExportType(RSContext * Context,ExportClass Class,const llvm::StringRef & Name)647 RSExportType::RSExportType(RSContext *Context,
648                            ExportClass Class,
649                            const llvm::StringRef &Name)
650     : RSExportable(Context, RSExportable::EX_TYPE),
651       mClass(Class),
652       // Make a copy on Name since memory stored @Name is either allocated in
653       // ASTContext or allocated in GetTypeName which will be destroyed later.
654       mName(Name.data(), Name.size()),
655       mLLVMType(NULL),
656       mSpecType(NULL) {
657   // Don't cache the type whose name start with '<'. Those type failed to
658   // get their name since constructing their name in GetTypeName() requiring
659   // complicated work.
660   if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX))
661     // TODO(zonr): Need to check whether the insertion is successful or not.
662     Context->insertExportType(llvm::StringRef(Name), this);
663   return;
664 }
665 
keep()666 bool RSExportType::keep() {
667   if (!RSExportable::keep())
668     return false;
669   // Invalidate converted LLVM type.
670   mLLVMType = NULL;
671   return true;
672 }
673 
equals(const RSExportable * E) const674 bool RSExportType::equals(const RSExportable *E) const {
675   CHECK_PARENT_EQUALITY(RSExportable, E);
676   return (static_cast<const RSExportType*>(E)->getClass() == getClass());
677 }
678 
~RSExportType()679 RSExportType::~RSExportType() {
680   delete mSpecType;
681 }
682 
683 /************************** RSExportPrimitiveType **************************/
684 llvm::ManagedStatic<RSExportPrimitiveType::RSSpecificTypeMapTy>
685 RSExportPrimitiveType::RSSpecificTypeMap;
686 
687 llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL;
688 
IsPrimitiveType(const clang::Type * T)689 bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) {
690   if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin))
691     return true;
692   else
693     return false;
694 }
695 
696 RSExportPrimitiveType::DataType
GetRSSpecificType(const llvm::StringRef & TypeName)697 RSExportPrimitiveType::GetRSSpecificType(const llvm::StringRef &TypeName) {
698   if (TypeName.empty())
699     return DataTypeUnknown;
700 
701   if (RSSpecificTypeMap->empty()) {
702 #define ENUM_RS_MATRIX_TYPE(type, cname, dim)                       \
703     RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
704 #include "RSMatrixTypeEnums.inc"
705 #define ENUM_RS_OBJECT_TYPE(type, cname)                            \
706     RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
707 #include "RSObjectTypeEnums.inc"
708   }
709 
710   RSSpecificTypeMapTy::const_iterator I = RSSpecificTypeMap->find(TypeName);
711   if (I == RSSpecificTypeMap->end())
712     return DataTypeUnknown;
713   else
714     return I->getValue();
715 }
716 
717 RSExportPrimitiveType::DataType
GetRSSpecificType(const clang::Type * T)718 RSExportPrimitiveType::GetRSSpecificType(const clang::Type *T) {
719   T = GET_CANONICAL_TYPE(T);
720   if ((T == NULL) || (T->getTypeClass() != clang::Type::Record))
721     return DataTypeUnknown;
722 
723   return GetRSSpecificType( RSExportType::GetTypeName(T) );
724 }
725 
IsRSMatrixType(DataType DT)726 bool RSExportPrimitiveType::IsRSMatrixType(DataType DT) {
727   return ((DT >= FirstRSMatrixType) && (DT <= LastRSMatrixType));
728 }
729 
IsRSObjectType(DataType DT)730 bool RSExportPrimitiveType::IsRSObjectType(DataType DT) {
731   return ((DT >= FirstRSObjectType) && (DT <= LastRSObjectType));
732 }
733 
IsStructureTypeWithRSObject(const clang::Type * T)734 bool RSExportPrimitiveType::IsStructureTypeWithRSObject(const clang::Type *T) {
735   bool RSObjectTypeSeen = false;
736   while (T && T->isArrayType()) {
737     T = T->getArrayElementTypeNoTypeQual();
738   }
739 
740   const clang::RecordType *RT = T->getAsStructureType();
741   if (!RT) {
742     return false;
743   }
744   const clang::RecordDecl *RD = RT->getDecl();
745   RD = RD->getDefinition();
746   for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
747          FE = RD->field_end();
748        FI != FE;
749        FI++) {
750     // We just look through all field declarations to see if we find a
751     // declaration for an RS object type (or an array of one).
752     const clang::FieldDecl *FD = *FI;
753     const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
754     while (FT && FT->isArrayType()) {
755       FT = FT->getArrayElementTypeNoTypeQual();
756     }
757 
758     RSExportPrimitiveType::DataType DT = GetRSSpecificType(FT);
759     if (IsRSObjectType(DT)) {
760       // RS object types definitely need to be zero-initialized
761       RSObjectTypeSeen = true;
762     } else {
763       switch (DT) {
764         case RSExportPrimitiveType::DataTypeRSMatrix2x2:
765         case RSExportPrimitiveType::DataTypeRSMatrix3x3:
766         case RSExportPrimitiveType::DataTypeRSMatrix4x4:
767           // Matrix types should get zero-initialized as well
768           RSObjectTypeSeen = true;
769           break;
770         default:
771           // Ignore all other primitive types
772           break;
773       }
774       while (FT && FT->isArrayType()) {
775         FT = FT->getArrayElementTypeNoTypeQual();
776       }
777       if (FT->isStructureType()) {
778         // Recursively handle structs of structs (even though these can't
779         // be exported, it is possible for a user to have them internally).
780         RSObjectTypeSeen |= IsStructureTypeWithRSObject(FT);
781       }
782     }
783   }
784 
785   return RSObjectTypeSeen;
786 }
787 
788 const size_t RSExportPrimitiveType::SizeOfDataTypeInBits[] = {
789 #define ENUM_RS_DATA_TYPE(type, cname, bits)  \
790   bits,
791 #include "RSDataTypeEnums.inc"
792   0   // DataTypeMax
793 };
794 
GetSizeInBits(const RSExportPrimitiveType * EPT)795 size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) {
796   slangAssert(((EPT->getType() > DataTypeUnknown) &&
797                (EPT->getType() < DataTypeMax)) &&
798               "RSExportPrimitiveType::GetSizeInBits : unknown data type");
799   return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ];
800 }
801 
802 RSExportPrimitiveType::DataType
GetDataType(RSContext * Context,const clang::Type * T)803 RSExportPrimitiveType::GetDataType(RSContext *Context, const clang::Type *T) {
804   if (T == NULL)
805     return DataTypeUnknown;
806 
807   switch (T->getTypeClass()) {
808     case clang::Type::Builtin: {
809       const clang::BuiltinType *BT =
810         UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
811       switch (BT->getKind()) {
812 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
813         case builtin_type: {                                  \
814           return DataType ## type;                            \
815         }
816 #include "RSClangBuiltinEnums.inc"
817         // The size of type WChar depend on platform so we abandon the support
818         // to them.
819         default: {
820           clang::Diagnostic *Diags = Context->getDiagnostics();
821           Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
822                             "built-in type cannot be exported: '%0'"))
823               << T->getTypeClassName();
824           break;
825         }
826       }
827       break;
828     }
829     case clang::Type::Record: {
830       // must be RS object type
831       return RSExportPrimitiveType::GetRSSpecificType(T);
832     }
833     default: {
834       clang::Diagnostic *Diags = Context->getDiagnostics();
835       Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
836                         "primitive type cannot be exported: '%0'"))
837           << T->getTypeClassName();
838       break;
839     }
840   }
841 
842   return DataTypeUnknown;
843 }
844 
845 RSExportPrimitiveType
Create(RSContext * Context,const clang::Type * T,const llvm::StringRef & TypeName,DataKind DK,bool Normalized)846 *RSExportPrimitiveType::Create(RSContext *Context,
847                                const clang::Type *T,
848                                const llvm::StringRef &TypeName,
849                                DataKind DK,
850                                bool Normalized) {
851   DataType DT = GetDataType(Context, T);
852 
853   if ((DT == DataTypeUnknown) || TypeName.empty())
854     return NULL;
855   else
856     return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName,
857                                      DT, DK, Normalized);
858 }
859 
Create(RSContext * Context,const clang::Type * T,DataKind DK)860 RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
861                                                      const clang::Type *T,
862                                                      DataKind DK) {
863   llvm::StringRef TypeName;
864   if (RSExportType::NormalizeType(T, TypeName, Context->getDiagnostics(), NULL)
865       && IsPrimitiveType(T)) {
866     return Create(Context, T, TypeName, DK);
867   } else {
868     return NULL;
869   }
870 }
871 
convertToLLVMType() const872 llvm::Type *RSExportPrimitiveType::convertToLLVMType() const {
873   llvm::LLVMContext &C = getRSContext()->getLLVMContext();
874 
875   if (isRSObjectType()) {
876     // struct {
877     //   int *p;
878     // } __attribute__((packed, aligned(pointer_size)))
879     //
880     // which is
881     //
882     // <{ [1 x i32] }> in LLVM
883     //
884     if (RSObjectLLVMType == NULL) {
885       std::vector<llvm::Type *> Elements;
886       Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1));
887       RSObjectLLVMType = llvm::StructType::get(C, Elements, true);
888     }
889     return RSObjectLLVMType;
890   }
891 
892   switch (mType) {
893     case DataTypeFloat32: {
894       return llvm::Type::getFloatTy(C);
895       break;
896     }
897     case DataTypeFloat64: {
898       return llvm::Type::getDoubleTy(C);
899       break;
900     }
901     case DataTypeBoolean: {
902       return llvm::Type::getInt1Ty(C);
903       break;
904     }
905     case DataTypeSigned8:
906     case DataTypeUnsigned8: {
907       return llvm::Type::getInt8Ty(C);
908       break;
909     }
910     case DataTypeSigned16:
911     case DataTypeUnsigned16:
912     case DataTypeUnsigned565:
913     case DataTypeUnsigned5551:
914     case DataTypeUnsigned4444: {
915       return llvm::Type::getInt16Ty(C);
916       break;
917     }
918     case DataTypeSigned32:
919     case DataTypeUnsigned32: {
920       return llvm::Type::getInt32Ty(C);
921       break;
922     }
923     case DataTypeSigned64:
924     case DataTypeUnsigned64: {
925       return llvm::Type::getInt64Ty(C);
926       break;
927     }
928     default: {
929       slangAssert(false && "Unknown data type");
930     }
931   }
932 
933   return NULL;
934 }
935 
convertToSpecType() const936 union RSType *RSExportPrimitiveType::convertToSpecType() const {
937   llvm::OwningPtr<union RSType> ST(new union RSType);
938   RS_TYPE_SET_CLASS(ST, RS_TC_Primitive);
939   // enum RSExportPrimitiveType::DataType is synced with enum RSDataType in
940   // slang_rs_type_spec.h
941   RS_PRIMITIVE_TYPE_SET_DATA_TYPE(ST, getType());
942   return ST.take();
943 }
944 
equals(const RSExportable * E) const945 bool RSExportPrimitiveType::equals(const RSExportable *E) const {
946   CHECK_PARENT_EQUALITY(RSExportType, E);
947   return (static_cast<const RSExportPrimitiveType*>(E)->getType() == getType());
948 }
949 
950 /**************************** RSExportPointerType ****************************/
951 
952 RSExportPointerType
Create(RSContext * Context,const clang::PointerType * PT,const llvm::StringRef & TypeName)953 *RSExportPointerType::Create(RSContext *Context,
954                              const clang::PointerType *PT,
955                              const llvm::StringRef &TypeName) {
956   const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
957   const RSExportType *PointeeET;
958 
959   if (PointeeType->getTypeClass() != clang::Type::Pointer) {
960     PointeeET = RSExportType::Create(Context, PointeeType);
961   } else {
962     // Double or higher dimension of pointer, export as int*
963     PointeeET = RSExportPrimitiveType::Create(Context,
964                     Context->getASTContext().IntTy.getTypePtr());
965   }
966 
967   if (PointeeET == NULL) {
968     // Error diagnostic is emitted for corresponding pointee type
969     return NULL;
970   }
971 
972   return new RSExportPointerType(Context, TypeName, PointeeET);
973 }
974 
convertToLLVMType() const975 llvm::Type *RSExportPointerType::convertToLLVMType() const {
976   llvm::Type *PointeeType = mPointeeType->getLLVMType();
977   return llvm::PointerType::getUnqual(PointeeType);
978 }
979 
convertToSpecType() const980 union RSType *RSExportPointerType::convertToSpecType() const {
981   llvm::OwningPtr<union RSType> ST(new union RSType);
982 
983   RS_TYPE_SET_CLASS(ST, RS_TC_Pointer);
984   RS_POINTER_TYPE_SET_POINTEE_TYPE(ST, getPointeeType()->getSpecType());
985 
986   if (RS_POINTER_TYPE_GET_POINTEE_TYPE(ST) != NULL)
987     return ST.take();
988   else
989     return NULL;
990 }
991 
keep()992 bool RSExportPointerType::keep() {
993   if (!RSExportType::keep())
994     return false;
995   const_cast<RSExportType*>(mPointeeType)->keep();
996   return true;
997 }
998 
equals(const RSExportable * E) const999 bool RSExportPointerType::equals(const RSExportable *E) const {
1000   CHECK_PARENT_EQUALITY(RSExportType, E);
1001   return (static_cast<const RSExportPointerType*>(E)
1002               ->getPointeeType()->equals(getPointeeType()));
1003 }
1004 
1005 /***************************** RSExportVectorType *****************************/
1006 llvm::StringRef
GetTypeName(const clang::ExtVectorType * EVT)1007 RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) {
1008   const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
1009 
1010   if ((ElementType->getTypeClass() != clang::Type::Builtin))
1011     return llvm::StringRef();
1012 
1013   const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(const clang::BuiltinType,
1014                                                   ElementType);
1015   if ((EVT->getNumElements() < 1) ||
1016       (EVT->getNumElements() > 4))
1017     return llvm::StringRef();
1018 
1019   switch (BT->getKind()) {
1020     // Compiler is smart enough to optimize following *big if branches* since
1021     // they all become "constant comparison" after macro expansion
1022 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname)  \
1023     case builtin_type: {                                      \
1024       const char *Name[] = { cname"2", cname"3", cname"4" };  \
1025       return Name[EVT->getNumElements() - 2];                 \
1026       break;                                                  \
1027     }
1028 #include "RSClangBuiltinEnums.inc"
1029     default: {
1030       return llvm::StringRef();
1031     }
1032   }
1033 }
1034 
Create(RSContext * Context,const clang::ExtVectorType * EVT,const llvm::StringRef & TypeName,DataKind DK,bool Normalized)1035 RSExportVectorType *RSExportVectorType::Create(RSContext *Context,
1036                                                const clang::ExtVectorType *EVT,
1037                                                const llvm::StringRef &TypeName,
1038                                                DataKind DK,
1039                                                bool Normalized) {
1040   slangAssert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector);
1041 
1042   const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
1043   RSExportPrimitiveType::DataType DT =
1044       RSExportPrimitiveType::GetDataType(Context, ElementType);
1045 
1046   if (DT != RSExportPrimitiveType::DataTypeUnknown)
1047     return new RSExportVectorType(Context,
1048                                   TypeName,
1049                                   DT,
1050                                   DK,
1051                                   Normalized,
1052                                   EVT->getNumElements());
1053   else
1054     return NULL;
1055 }
1056 
convertToLLVMType() const1057 llvm::Type *RSExportVectorType::convertToLLVMType() const {
1058   llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType();
1059   return llvm::VectorType::get(ElementType, getNumElement());
1060 }
1061 
convertToSpecType() const1062 union RSType *RSExportVectorType::convertToSpecType() const {
1063   llvm::OwningPtr<union RSType> ST(new union RSType);
1064 
1065   RS_TYPE_SET_CLASS(ST, RS_TC_Vector);
1066   RS_VECTOR_TYPE_SET_ELEMENT_TYPE(ST, getType());
1067   RS_VECTOR_TYPE_SET_VECTOR_SIZE(ST, getNumElement());
1068 
1069   return ST.take();
1070 }
1071 
equals(const RSExportable * E) const1072 bool RSExportVectorType::equals(const RSExportable *E) const {
1073   CHECK_PARENT_EQUALITY(RSExportPrimitiveType, E);
1074   return (static_cast<const RSExportVectorType*>(E)->getNumElement()
1075               == getNumElement());
1076 }
1077 
1078 /***************************** RSExportMatrixType *****************************/
Create(RSContext * Context,const clang::RecordType * RT,const llvm::StringRef & TypeName,unsigned Dim)1079 RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context,
1080                                                const clang::RecordType *RT,
1081                                                const llvm::StringRef &TypeName,
1082                                                unsigned Dim) {
1083   slangAssert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record));
1084   slangAssert((Dim > 1) && "Invalid dimension of matrix");
1085 
1086   // Check whether the struct rs_matrix is in our expected form (but assume it's
1087   // correct if we're not sure whether it's correct or not)
1088   const clang::RecordDecl* RD = RT->getDecl();
1089   RD = RD->getDefinition();
1090   if (RD != NULL) {
1091     clang::Diagnostic *Diags = Context->getDiagnostics();
1092     const clang::SourceManager *SM = Context->getSourceManager();
1093     // Find definition, perform further examination
1094     if (RD->field_empty()) {
1095       Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1096                     Diags->getCustomDiagID(clang::Diagnostic::Error,
1097                         "invalid matrix struct: must have 1 field for saving "
1098                         "values: '%0'"))
1099            << RD->getName();
1100       return NULL;
1101     }
1102 
1103     clang::RecordDecl::field_iterator FIT = RD->field_begin();
1104     const clang::FieldDecl *FD = *FIT;
1105     const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1106     if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
1107       Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1108                     Diags->getCustomDiagID(clang::Diagnostic::Error,
1109                         "invalid matrix struct: first field should be an "
1110                         "array with constant size: '%0'"))
1111            << RD->getName();
1112       return NULL;
1113     }
1114     const clang::ConstantArrayType *CAT =
1115       static_cast<const clang::ConstantArrayType *>(FT);
1116     const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1117     if ((ElementType == NULL) ||
1118         (ElementType->getTypeClass() != clang::Type::Builtin) ||
1119         (static_cast<const clang::BuiltinType *>(ElementType)->getKind()
1120           != clang::BuiltinType::Float)) {
1121       Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1122                     Diags->getCustomDiagID(clang::Diagnostic::Error,
1123                         "invalid matrix struct: first field should be a "
1124                         "float array: '%0'"))
1125            << RD->getName();
1126       return NULL;
1127     }
1128 
1129     if (CAT->getSize() != Dim * Dim) {
1130       Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1131                     Diags->getCustomDiagID(clang::Diagnostic::Error,
1132                         "invalid matrix struct: first field should be an "
1133                         "array with size %0: '%1'"))
1134            << Dim * Dim
1135            << RD->getName();
1136       return NULL;
1137     }
1138 
1139     FIT++;
1140     if (FIT != RD->field_end()) {
1141       Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM),
1142                     Diags->getCustomDiagID(clang::Diagnostic::Error,
1143                         "invalid matrix struct: must have exactly 1 field: "
1144                         "'%0'"))
1145            << RD->getName();
1146       return NULL;
1147     }
1148   }
1149 
1150   return new RSExportMatrixType(Context, TypeName, Dim);
1151 }
1152 
convertToLLVMType() const1153 llvm::Type *RSExportMatrixType::convertToLLVMType() const {
1154   // Construct LLVM type:
1155   // struct {
1156   //  float X[mDim * mDim];
1157   // }
1158 
1159   llvm::LLVMContext &C = getRSContext()->getLLVMContext();
1160   llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C),
1161                                             mDim * mDim);
1162   return llvm::StructType::get(C, X, false);
1163 }
1164 
convertToSpecType() const1165 union RSType *RSExportMatrixType::convertToSpecType() const {
1166   llvm::OwningPtr<union RSType> ST(new union RSType);
1167   RS_TYPE_SET_CLASS(ST, RS_TC_Matrix);
1168   switch (getDim()) {
1169     case 2: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix2x2); break;
1170     case 3: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix3x3); break;
1171     case 4: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix4x4); break;
1172     default: slangAssert(false && "Matrix type with unsupported dimension.");
1173   }
1174   return ST.take();
1175 }
1176 
equals(const RSExportable * E) const1177 bool RSExportMatrixType::equals(const RSExportable *E) const {
1178   CHECK_PARENT_EQUALITY(RSExportType, E);
1179   return (static_cast<const RSExportMatrixType*>(E)->getDim() == getDim());
1180 }
1181 
1182 /************************* RSExportConstantArrayType *************************/
1183 RSExportConstantArrayType
Create(RSContext * Context,const clang::ConstantArrayType * CAT)1184 *RSExportConstantArrayType::Create(RSContext *Context,
1185                                    const clang::ConstantArrayType *CAT) {
1186   slangAssert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray);
1187 
1188   slangAssert((CAT->getSize().getActiveBits() < 32) && "array too large");
1189 
1190   unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue());
1191   slangAssert((Size > 0) && "Constant array should have size greater than 0");
1192 
1193   const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1194   RSExportType *ElementET = RSExportType::Create(Context, ElementType);
1195 
1196   if (ElementET == NULL) {
1197     return NULL;
1198   }
1199 
1200   return new RSExportConstantArrayType(Context,
1201                                        ElementET,
1202                                        Size);
1203 }
1204 
convertToLLVMType() const1205 llvm::Type *RSExportConstantArrayType::convertToLLVMType() const {
1206   return llvm::ArrayType::get(mElementType->getLLVMType(), getSize());
1207 }
1208 
convertToSpecType() const1209 union RSType *RSExportConstantArrayType::convertToSpecType() const {
1210   llvm::OwningPtr<union RSType> ST(new union RSType);
1211 
1212   RS_TYPE_SET_CLASS(ST, RS_TC_ConstantArray);
1213   RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_TYPE(
1214       ST, getElementType()->getSpecType());
1215   RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_SIZE(ST, getSize());
1216 
1217   if (RS_CONSTANT_ARRAY_TYPE_GET_ELEMENT_TYPE(ST) != NULL)
1218     return ST.take();
1219   else
1220     return NULL;
1221 }
1222 
keep()1223 bool RSExportConstantArrayType::keep() {
1224   if (!RSExportType::keep())
1225     return false;
1226   const_cast<RSExportType*>(mElementType)->keep();
1227   return true;
1228 }
1229 
equals(const RSExportable * E) const1230 bool RSExportConstantArrayType::equals(const RSExportable *E) const {
1231   CHECK_PARENT_EQUALITY(RSExportType, E);
1232   const RSExportConstantArrayType *RHS =
1233       static_cast<const RSExportConstantArrayType*>(E);
1234   return ((getSize() == RHS->getSize()) &&
1235           (getElementType()->equals(RHS->getElementType())));
1236 }
1237 
1238 /**************************** RSExportRecordType ****************************/
Create(RSContext * Context,const clang::RecordType * RT,const llvm::StringRef & TypeName,bool mIsArtificial)1239 RSExportRecordType *RSExportRecordType::Create(RSContext *Context,
1240                                                const clang::RecordType *RT,
1241                                                const llvm::StringRef &TypeName,
1242                                                bool mIsArtificial) {
1243   slangAssert(RT != NULL && RT->getTypeClass() == clang::Type::Record);
1244 
1245   const clang::RecordDecl *RD = RT->getDecl();
1246   slangAssert(RD->isStruct());
1247 
1248   RD = RD->getDefinition();
1249   if (RD == NULL) {
1250     slangAssert(false && "struct is not defined in this module");
1251     return NULL;
1252   }
1253 
1254   // Struct layout construct by clang. We rely on this for obtaining the
1255   // alloc size of a struct and offset of every field in that struct.
1256   const clang::ASTRecordLayout *RL =
1257       &Context->getASTContext().getASTRecordLayout(RD);
1258   slangAssert((RL != NULL) &&
1259       "Failed to retrieve the struct layout from Clang.");
1260 
1261   RSExportRecordType *ERT =
1262       new RSExportRecordType(Context,
1263                              TypeName,
1264                              RD->hasAttr<clang::PackedAttr>(),
1265                              mIsArtificial,
1266                              RL->getSize().getQuantity());
1267   unsigned int Index = 0;
1268 
1269   for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1270            FE = RD->field_end();
1271        FI != FE;
1272        FI++, Index++) {
1273     clang::Diagnostic *Diags = Context->getDiagnostics();
1274 
1275     // FIXME: All fields should be primitive type
1276     slangAssert((*FI)->getKind() == clang::Decl::Field);
1277     clang::FieldDecl *FD = *FI;
1278 
1279     if (FD->isBitField()) {
1280       return NULL;
1281     }
1282 
1283     // Type
1284     RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
1285 
1286     if (ET != NULL) {
1287       ERT->mFields.push_back(
1288           new Field(ET, FD->getName(), ERT,
1289                     static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
1290     } else {
1291       Diags->Report(clang::FullSourceLoc(RD->getLocation(),
1292                                          Diags->getSourceManager()),
1293                     Diags->getCustomDiagID(clang::Diagnostic::Error,
1294                     "field type cannot be exported: '%0.%1'"))
1295           << RD->getName()
1296           << FD->getName();
1297       return NULL;
1298     }
1299   }
1300 
1301   return ERT;
1302 }
1303 
convertToLLVMType() const1304 llvm::Type *RSExportRecordType::convertToLLVMType() const {
1305   // Create an opaque type since struct may reference itself recursively.
1306 
1307   // TODO(sliao): LLVM took out the OpaqueType. Any other to migrate to?
1308   std::vector<llvm::Type*> FieldTypes;
1309 
1310   for (const_field_iterator FI = fields_begin(), FE = fields_end();
1311        FI != FE;
1312        FI++) {
1313     const Field *F = *FI;
1314     const RSExportType *FET = F->getType();
1315 
1316     FieldTypes.push_back(FET->getLLVMType());
1317   }
1318 
1319   llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(),
1320                                                FieldTypes,
1321                                                mIsPacked);
1322   if (ST != NULL) {
1323     return ST;
1324   } else {
1325     return NULL;
1326   }
1327 }
1328 
convertToSpecType() const1329 union RSType *RSExportRecordType::convertToSpecType() const {
1330   unsigned NumFields = getFields().size();
1331   unsigned AllocSize = sizeof(union RSType) +
1332                        sizeof(struct RSRecordField) * NumFields;
1333   llvm::OwningPtr<union RSType> ST(
1334       reinterpret_cast<union RSType*>(operator new(AllocSize)));
1335 
1336   ::memset(ST.get(), 0, AllocSize);
1337 
1338   RS_TYPE_SET_CLASS(ST, RS_TC_Record);
1339   RS_RECORD_TYPE_SET_NAME(ST, getName().c_str());
1340   RS_RECORD_TYPE_SET_NUM_FIELDS(ST, NumFields);
1341 
1342   setSpecTypeTemporarily(ST.get());
1343 
1344   unsigned FieldIdx = 0;
1345   for (const_field_iterator FI = fields_begin(), FE = fields_end();
1346        FI != FE;
1347        FI++, FieldIdx++) {
1348     const Field *F = *FI;
1349 
1350     RS_RECORD_TYPE_SET_FIELD_NAME(ST, FieldIdx, F->getName().c_str());
1351     RS_RECORD_TYPE_SET_FIELD_TYPE(ST, FieldIdx, F->getType()->getSpecType());
1352 
1353     enum RSDataKind DK = RS_DK_User;
1354     if ((F->getType()->getClass() == ExportClassPrimitive) ||
1355         (F->getType()->getClass() == ExportClassVector)) {
1356       const RSExportPrimitiveType *EPT =
1357         static_cast<const RSExportPrimitiveType*>(F->getType());
1358       // enum RSExportPrimitiveType::DataKind is synced with enum RSDataKind in
1359       // slang_rs_type_spec.h
1360       DK = static_cast<enum RSDataKind>(EPT->getKind());
1361     }
1362     RS_RECORD_TYPE_SET_FIELD_DATA_KIND(ST, FieldIdx, DK);
1363   }
1364 
1365   // TODO(slang): Check whether all fields were created normally.
1366 
1367   return ST.take();
1368 }
1369 
keep()1370 bool RSExportRecordType::keep() {
1371   if (!RSExportType::keep())
1372     return false;
1373   for (std::list<const Field*>::iterator I = mFields.begin(),
1374           E = mFields.end();
1375        I != E;
1376        I++) {
1377     const_cast<RSExportType*>((*I)->getType())->keep();
1378   }
1379   return true;
1380 }
1381 
equals(const RSExportable * E) const1382 bool RSExportRecordType::equals(const RSExportable *E) const {
1383   CHECK_PARENT_EQUALITY(RSExportType, E);
1384 
1385   const RSExportRecordType *ERT = static_cast<const RSExportRecordType*>(E);
1386 
1387   if (ERT->getFields().size() != getFields().size())
1388     return false;
1389 
1390   const_field_iterator AI = fields_begin(), BI = ERT->fields_begin();
1391 
1392   for (unsigned i = 0, e = getFields().size(); i != e; i++) {
1393     if (!(*AI)->getType()->equals((*BI)->getType()))
1394       return false;
1395     AI++;
1396     BI++;
1397   }
1398 
1399   return true;
1400 }
1401 
1402 }  // namespace slang
1403