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