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