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