slang_rs_export_type.cpp revision a67e4451d0d03b4ab7866b64807d95a8399c73a0
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 41namespace slang { 42 43namespace { 44 45static 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 52static 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 80static 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 117static 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). 276static 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 285static 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 ******************************/ 392bool 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 421bool 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 429const clang::Type 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 446llvm::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 531RSExportType *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 621RSExportType *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 629RSExportType *RSExportType::CreateFromDecl(RSContext *Context, 630 const clang::VarDecl *VD) { 631 return RSExportType::Create(Context, GetTypeOfDecl(VD)); 632} 633 634size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) { 635 return ET->getRSContext()->getTargetData()->getTypeStoreSize( 636 ET->getLLVMType()); 637} 638 639size_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 647RSExportType::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 666bool RSExportType::keep() { 667 if (!RSExportable::keep()) 668 return false; 669 // Invalidate converted LLVM type. 670 mLLVMType = NULL; 671 return true; 672} 673 674bool RSExportType::equals(const RSExportable *E) const { 675 CHECK_PARENT_EQUALITY(RSExportable, E); 676 return (static_cast<const RSExportType*>(E)->getClass() == getClass()); 677} 678 679RSExportType::~RSExportType() { 680 delete mSpecType; 681} 682 683/************************** RSExportPrimitiveType **************************/ 684llvm::ManagedStatic<RSExportPrimitiveType::RSSpecificTypeMapTy> 685RSExportPrimitiveType::RSSpecificTypeMap; 686 687llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL; 688 689bool 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 696RSExportPrimitiveType::DataType 697RSExportPrimitiveType::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 717RSExportPrimitiveType::DataType 718RSExportPrimitiveType::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 726bool RSExportPrimitiveType::IsRSMatrixType(DataType DT) { 727 return ((DT >= FirstRSMatrixType) && (DT <= LastRSMatrixType)); 728} 729 730bool RSExportPrimitiveType::IsRSObjectType(DataType DT) { 731 return ((DT >= FirstRSObjectType) && (DT <= LastRSObjectType)); 732} 733 734bool 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 788const size_t RSExportPrimitiveType::SizeOfDataTypeInBits[] = { 789#define ENUM_RS_DATA_TYPE(type, cname, bits) \ 790 bits, 791#include "RSDataTypeEnums.inc" 792 0 // DataTypeMax 793}; 794 795size_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 802RSExportPrimitiveType::DataType 803RSExportPrimitiveType::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 845RSExportPrimitiveType 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 860RSExportPrimitiveType *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 872llvm::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 936union 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 945bool 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 952RSExportPointerType 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 975llvm::Type *RSExportPointerType::convertToLLVMType() const { 976 llvm::Type *PointeeType = mPointeeType->getLLVMType(); 977 return llvm::PointerType::getUnqual(PointeeType); 978} 979 980union 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 992bool RSExportPointerType::keep() { 993 if (!RSExportType::keep()) 994 return false; 995 const_cast<RSExportType*>(mPointeeType)->keep(); 996 return true; 997} 998 999bool 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 *****************************/ 1006llvm::StringRef 1007RSExportVectorType::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 1035RSExportVectorType *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 1057llvm::Type *RSExportVectorType::convertToLLVMType() const { 1058 llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType(); 1059 return llvm::VectorType::get(ElementType, getNumElement()); 1060} 1061 1062union 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 1072bool 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 *****************************/ 1079RSExportMatrixType *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 1153llvm::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 1165union 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 1177bool 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 *************************/ 1183RSExportConstantArrayType 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 1205llvm::Type *RSExportConstantArrayType::convertToLLVMType() const { 1206 return llvm::ArrayType::get(mElementType->getLLVMType(), getSize()); 1207} 1208 1209union 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 1223bool RSExportConstantArrayType::keep() { 1224 if (!RSExportType::keep()) 1225 return false; 1226 const_cast<RSExportType*>(mElementType)->keep(); 1227 return true; 1228} 1229 1230bool 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 ****************************/ 1239RSExportRecordType *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 delete ERT; 1281 return NULL; 1282 } 1283 1284 // Type 1285 RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD); 1286 1287 if (ET != NULL) { 1288 ERT->mFields.push_back( 1289 new Field(ET, FD->getName(), ERT, 1290 static_cast<size_t>(RL->getFieldOffset(Index) >> 3))); 1291 } else { 1292 Diags->Report(clang::FullSourceLoc(RD->getLocation(), 1293 Diags->getSourceManager()), 1294 Diags->getCustomDiagID(clang::Diagnostic::Error, 1295 "field type cannot be exported: '%0.%1'")) 1296 << RD->getName() 1297 << FD->getName(); 1298 delete ERT; 1299 return NULL; 1300 } 1301 } 1302 1303 return ERT; 1304} 1305 1306llvm::Type *RSExportRecordType::convertToLLVMType() const { 1307 // Create an opaque type since struct may reference itself recursively. 1308 1309 // TODO(sliao): LLVM took out the OpaqueType. Any other to migrate to? 1310 std::vector<llvm::Type*> FieldTypes; 1311 1312 for (const_field_iterator FI = fields_begin(), FE = fields_end(); 1313 FI != FE; 1314 FI++) { 1315 const Field *F = *FI; 1316 const RSExportType *FET = F->getType(); 1317 1318 FieldTypes.push_back(FET->getLLVMType()); 1319 } 1320 1321 llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(), 1322 FieldTypes, 1323 mIsPacked); 1324 if (ST != NULL) { 1325 return ST; 1326 } else { 1327 return NULL; 1328 } 1329} 1330 1331union RSType *RSExportRecordType::convertToSpecType() const { 1332 unsigned NumFields = getFields().size(); 1333 unsigned AllocSize = sizeof(union RSType) + 1334 sizeof(struct RSRecordField) * NumFields; 1335 llvm::OwningPtr<union RSType> ST( 1336 reinterpret_cast<union RSType*>(operator new(AllocSize))); 1337 1338 ::memset(ST.get(), 0, AllocSize); 1339 1340 RS_TYPE_SET_CLASS(ST, RS_TC_Record); 1341 RS_RECORD_TYPE_SET_NAME(ST, getName().c_str()); 1342 RS_RECORD_TYPE_SET_NUM_FIELDS(ST, NumFields); 1343 1344 setSpecTypeTemporarily(ST.get()); 1345 1346 unsigned FieldIdx = 0; 1347 for (const_field_iterator FI = fields_begin(), FE = fields_end(); 1348 FI != FE; 1349 FI++, FieldIdx++) { 1350 const Field *F = *FI; 1351 1352 RS_RECORD_TYPE_SET_FIELD_NAME(ST, FieldIdx, F->getName().c_str()); 1353 RS_RECORD_TYPE_SET_FIELD_TYPE(ST, FieldIdx, F->getType()->getSpecType()); 1354 1355 enum RSDataKind DK = RS_DK_User; 1356 if ((F->getType()->getClass() == ExportClassPrimitive) || 1357 (F->getType()->getClass() == ExportClassVector)) { 1358 const RSExportPrimitiveType *EPT = 1359 static_cast<const RSExportPrimitiveType*>(F->getType()); 1360 // enum RSExportPrimitiveType::DataKind is synced with enum RSDataKind in 1361 // slang_rs_type_spec.h 1362 DK = static_cast<enum RSDataKind>(EPT->getKind()); 1363 } 1364 RS_RECORD_TYPE_SET_FIELD_DATA_KIND(ST, FieldIdx, DK); 1365 } 1366 1367 // TODO(slang): Check whether all fields were created normally. 1368 1369 return ST.take(); 1370} 1371 1372bool RSExportRecordType::keep() { 1373 if (!RSExportType::keep()) 1374 return false; 1375 for (std::list<const Field*>::iterator I = mFields.begin(), 1376 E = mFields.end(); 1377 I != E; 1378 I++) { 1379 const_cast<RSExportType*>((*I)->getType())->keep(); 1380 } 1381 return true; 1382} 1383 1384bool RSExportRecordType::equals(const RSExportable *E) const { 1385 CHECK_PARENT_EQUALITY(RSExportType, E); 1386 1387 const RSExportRecordType *ERT = static_cast<const RSExportRecordType*>(E); 1388 1389 if (ERT->getFields().size() != getFields().size()) 1390 return false; 1391 1392 const_field_iterator AI = fields_begin(), BI = ERT->fields_begin(); 1393 1394 for (unsigned i = 0, e = getFields().size(); i != e; i++) { 1395 if (!(*AI)->getType()->equals((*BI)->getType())) 1396 return false; 1397 AI++; 1398 BI++; 1399 } 1400 1401 return true; 1402} 1403 1404} // namespace slang 1405