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