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