slang_rs_export_type.cpp revision 78e69cb06b9b0683b2ac9dcafde87b867690ef2f
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), 593 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), 601 TypeName); 602 break; 603 } 604 case clang::Type::ConstantArray: { 605 ET = RSExportConstantArrayType::Create( 606 Context, 607 UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T)); 608 break; 609 } 610 default: { 611 clang::Diagnostic *Diags = Context->getDiagnostics(); 612 Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error, 613 "unknown type cannot be exported: '%0'")) 614 << T->getTypeClassName(); 615 break; 616 } 617 } 618 619 return ET; 620} 621 622RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) { 623 llvm::StringRef TypeName; 624 if (NormalizeType(T, TypeName, Context->getDiagnostics(), NULL)) 625 return Create(Context, T, TypeName); 626 else 627 return NULL; 628} 629 630RSExportType *RSExportType::CreateFromDecl(RSContext *Context, 631 const clang::VarDecl *VD) { 632 return RSExportType::Create(Context, GetTypeOfDecl(VD)); 633} 634 635size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) { 636 return ET->getRSContext()->getTargetData()->getTypeStoreSize( 637 ET->getLLVMType()); 638} 639 640size_t RSExportType::GetTypeAllocSize(const RSExportType *ET) { 641 if (ET->getClass() == RSExportType::ExportClassRecord) 642 return static_cast<const RSExportRecordType*>(ET)->getAllocSize(); 643 else 644 return ET->getRSContext()->getTargetData()->getTypeAllocSize( 645 ET->getLLVMType()); 646} 647 648RSExportType::RSExportType(RSContext *Context, 649 ExportClass Class, 650 const llvm::StringRef &Name) 651 : RSExportable(Context, RSExportable::EX_TYPE), 652 mClass(Class), 653 // Make a copy on Name since memory stored @Name is either allocated in 654 // ASTContext or allocated in GetTypeName which will be destroyed later. 655 mName(Name.data(), Name.size()), 656 mLLVMType(NULL), 657 mSpecType(NULL) { 658 // Don't cache the type whose name start with '<'. Those type failed to 659 // get their name since constructing their name in GetTypeName() requiring 660 // complicated work. 661 if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX)) 662 // TODO(zonr): Need to check whether the insertion is successful or not. 663 Context->insertExportType(llvm::StringRef(Name), this); 664 return; 665} 666 667bool RSExportType::keep() { 668 if (!RSExportable::keep()) 669 return false; 670 // Invalidate converted LLVM type. 671 mLLVMType = NULL; 672 return true; 673} 674 675bool RSExportType::equals(const RSExportable *E) const { 676 CHECK_PARENT_EQUALITY(RSExportable, E); 677 return (static_cast<const RSExportType*>(E)->getClass() == getClass()); 678} 679 680RSExportType::~RSExportType() { 681 delete mSpecType; 682} 683 684/************************** RSExportPrimitiveType **************************/ 685llvm::ManagedStatic<RSExportPrimitiveType::RSSpecificTypeMapTy> 686RSExportPrimitiveType::RSSpecificTypeMap; 687 688llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL; 689 690bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) { 691 if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin)) 692 return true; 693 else 694 return false; 695} 696 697RSExportPrimitiveType::DataType 698RSExportPrimitiveType::GetRSSpecificType(const llvm::StringRef &TypeName) { 699 if (TypeName.empty()) 700 return DataTypeUnknown; 701 702 if (RSSpecificTypeMap->empty()) { 703#define ENUM_RS_MATRIX_TYPE(type, cname, dim) \ 704 RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type); 705#include "RSMatrixTypeEnums.inc" 706#define ENUM_RS_OBJECT_TYPE(type, cname) \ 707 RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type); 708#include "RSObjectTypeEnums.inc" 709 } 710 711 RSSpecificTypeMapTy::const_iterator I = RSSpecificTypeMap->find(TypeName); 712 if (I == RSSpecificTypeMap->end()) 713 return DataTypeUnknown; 714 else 715 return I->getValue(); 716} 717 718RSExportPrimitiveType::DataType 719RSExportPrimitiveType::GetRSSpecificType(const clang::Type *T) { 720 T = GET_CANONICAL_TYPE(T); 721 if ((T == NULL) || (T->getTypeClass() != clang::Type::Record)) 722 return DataTypeUnknown; 723 724 return GetRSSpecificType( RSExportType::GetTypeName(T) ); 725} 726 727bool RSExportPrimitiveType::IsRSMatrixType(DataType DT) { 728 return ((DT >= FirstRSMatrixType) && (DT <= LastRSMatrixType)); 729} 730 731bool RSExportPrimitiveType::IsRSObjectType(DataType DT) { 732 return ((DT >= FirstRSObjectType) && (DT <= LastRSObjectType)); 733} 734 735bool RSExportPrimitiveType::IsStructureTypeWithRSObject(const clang::Type *T) { 736 bool RSObjectTypeSeen = false; 737 while (T && T->isArrayType()) { 738 T = T->getArrayElementTypeNoTypeQual(); 739 } 740 741 const clang::RecordType *RT = T->getAsStructureType(); 742 if (!RT) { 743 return false; 744 } 745 const clang::RecordDecl *RD = RT->getDecl(); 746 RD = RD->getDefinition(); 747 for (clang::RecordDecl::field_iterator FI = RD->field_begin(), 748 FE = RD->field_end(); 749 FI != FE; 750 FI++) { 751 // We just look through all field declarations to see if we find a 752 // declaration for an RS object type (or an array of one). 753 const clang::FieldDecl *FD = *FI; 754 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD); 755 while (FT && FT->isArrayType()) { 756 FT = FT->getArrayElementTypeNoTypeQual(); 757 } 758 759 RSExportPrimitiveType::DataType DT = GetRSSpecificType(FT); 760 if (IsRSObjectType(DT)) { 761 // RS object types definitely need to be zero-initialized 762 RSObjectTypeSeen = true; 763 } else { 764 switch (DT) { 765 case RSExportPrimitiveType::DataTypeRSMatrix2x2: 766 case RSExportPrimitiveType::DataTypeRSMatrix3x3: 767 case RSExportPrimitiveType::DataTypeRSMatrix4x4: 768 // Matrix types should get zero-initialized as well 769 RSObjectTypeSeen = true; 770 break; 771 default: 772 // Ignore all other primitive types 773 break; 774 } 775 while (FT && FT->isArrayType()) { 776 FT = FT->getArrayElementTypeNoTypeQual(); 777 } 778 if (FT->isStructureType()) { 779 // Recursively handle structs of structs (even though these can't 780 // be exported, it is possible for a user to have them internally). 781 RSObjectTypeSeen |= IsStructureTypeWithRSObject(FT); 782 } 783 } 784 } 785 786 return RSObjectTypeSeen; 787} 788 789const size_t RSExportPrimitiveType::SizeOfDataTypeInBits[] = { 790#define ENUM_RS_DATA_TYPE(type, cname, bits) \ 791 bits, 792#include "RSDataTypeEnums.inc" 793 0 // DataTypeMax 794}; 795 796size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) { 797 slangAssert(((EPT->getType() > DataTypeUnknown) && 798 (EPT->getType() < DataTypeMax)) && 799 "RSExportPrimitiveType::GetSizeInBits : unknown data type"); 800 return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ]; 801} 802 803RSExportPrimitiveType::DataType 804RSExportPrimitiveType::GetDataType(RSContext *Context, const clang::Type *T) { 805 if (T == NULL) 806 return DataTypeUnknown; 807 808 switch (T->getTypeClass()) { 809 case clang::Type::Builtin: { 810 const clang::BuiltinType *BT = 811 UNSAFE_CAST_TYPE(const clang::BuiltinType, T); 812 switch (BT->getKind()) { 813#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname) \ 814 case builtin_type: { \ 815 return DataType ## type; \ 816 } 817#include "RSClangBuiltinEnums.inc" 818 // The size of type WChar depend on platform so we abandon the support 819 // to them. 820 default: { 821 clang::Diagnostic *Diags = Context->getDiagnostics(); 822 Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error, 823 "built-in type cannot be exported: '%0'")) 824 << T->getTypeClassName(); 825 break; 826 } 827 } 828 break; 829 } 830 case clang::Type::Record: { 831 // must be RS object type 832 return RSExportPrimitiveType::GetRSSpecificType(T); 833 } 834 default: { 835 clang::Diagnostic *Diags = Context->getDiagnostics(); 836 Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error, 837 "primitive type cannot be exported: '%0'")) 838 << T->getTypeClassName(); 839 break; 840 } 841 } 842 843 return DataTypeUnknown; 844} 845 846RSExportPrimitiveType 847*RSExportPrimitiveType::Create(RSContext *Context, 848 const clang::Type *T, 849 const llvm::StringRef &TypeName, 850 DataKind DK, 851 bool Normalized) { 852 DataType DT = GetDataType(Context, T); 853 854 if ((DT == DataTypeUnknown) || TypeName.empty()) 855 return NULL; 856 else 857 return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName, 858 DT, DK, Normalized); 859} 860 861RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context, 862 const clang::Type *T, 863 DataKind DK) { 864 llvm::StringRef TypeName; 865 if (RSExportType::NormalizeType(T, TypeName, Context->getDiagnostics(), NULL) 866 && IsPrimitiveType(T)) { 867 return Create(Context, T, TypeName, DK); 868 } else { 869 return NULL; 870 } 871} 872 873const llvm::Type *RSExportPrimitiveType::convertToLLVMType() const { 874 llvm::LLVMContext &C = getRSContext()->getLLVMContext(); 875 876 if (isRSObjectType()) { 877 // struct { 878 // int *p; 879 // } __attribute__((packed, aligned(pointer_size))) 880 // 881 // which is 882 // 883 // <{ [1 x i32] }> in LLVM 884 // 885 if (RSObjectLLVMType == NULL) { 886 std::vector<const llvm::Type *> Elements; 887 Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1)); 888 RSObjectLLVMType = llvm::StructType::get(C, Elements, true); 889 } 890 return RSObjectLLVMType; 891 } 892 893 switch (mType) { 894 case DataTypeFloat32: { 895 return llvm::Type::getFloatTy(C); 896 break; 897 } 898 case DataTypeFloat64: { 899 return llvm::Type::getDoubleTy(C); 900 break; 901 } 902 case DataTypeBoolean: { 903 return llvm::Type::getInt1Ty(C); 904 break; 905 } 906 case DataTypeSigned8: 907 case DataTypeUnsigned8: { 908 return llvm::Type::getInt8Ty(C); 909 break; 910 } 911 case DataTypeSigned16: 912 case DataTypeUnsigned16: 913 case DataTypeUnsigned565: 914 case DataTypeUnsigned5551: 915 case DataTypeUnsigned4444: { 916 return llvm::Type::getInt16Ty(C); 917 break; 918 } 919 case DataTypeSigned32: 920 case DataTypeUnsigned32: { 921 return llvm::Type::getInt32Ty(C); 922 break; 923 } 924 case DataTypeSigned64: 925 case DataTypeUnsigned64: { 926 return llvm::Type::getInt64Ty(C); 927 break; 928 } 929 default: { 930 slangAssert(false && "Unknown data type"); 931 } 932 } 933 934 return NULL; 935} 936 937union RSType *RSExportPrimitiveType::convertToSpecType() const { 938 llvm::OwningPtr<union RSType> ST(new union RSType); 939 RS_TYPE_SET_CLASS(ST, RS_TC_Primitive); 940 // enum RSExportPrimitiveType::DataType is synced with enum RSDataType in 941 // slang_rs_type_spec.h 942 RS_PRIMITIVE_TYPE_SET_DATA_TYPE(ST, getType()); 943 return ST.take(); 944} 945 946bool RSExportPrimitiveType::equals(const RSExportable *E) const { 947 CHECK_PARENT_EQUALITY(RSExportType, E); 948 return (static_cast<const RSExportPrimitiveType*>(E)->getType() == getType()); 949} 950 951/**************************** RSExportPointerType ****************************/ 952 953RSExportPointerType 954*RSExportPointerType::Create(RSContext *Context, 955 const clang::PointerType *PT, 956 const llvm::StringRef &TypeName) { 957 const clang::Type *PointeeType = GET_POINTEE_TYPE(PT); 958 const RSExportType *PointeeET; 959 960 if (PointeeType->getTypeClass() != clang::Type::Pointer) { 961 PointeeET = RSExportType::Create(Context, PointeeType); 962 } else { 963 // Double or higher dimension of pointer, export as int* 964 PointeeET = RSExportPrimitiveType::Create(Context, 965 Context->getASTContext().IntTy.getTypePtr()); 966 } 967 968 if (PointeeET == NULL) { 969 // Error diagnostic is emitted for corresponding pointee type 970 return NULL; 971 } 972 973 return new RSExportPointerType(Context, TypeName, PointeeET); 974} 975 976const llvm::Type *RSExportPointerType::convertToLLVMType() const { 977 const llvm::Type *PointeeType = mPointeeType->getLLVMType(); 978 return llvm::PointerType::getUnqual(PointeeType); 979} 980 981union RSType *RSExportPointerType::convertToSpecType() const { 982 llvm::OwningPtr<union RSType> ST(new union RSType); 983 984 RS_TYPE_SET_CLASS(ST, RS_TC_Pointer); 985 RS_POINTER_TYPE_SET_POINTEE_TYPE(ST, getPointeeType()->getSpecType()); 986 987 if (RS_POINTER_TYPE_GET_POINTEE_TYPE(ST) != NULL) 988 return ST.take(); 989 else 990 return NULL; 991} 992 993bool RSExportPointerType::keep() { 994 if (!RSExportType::keep()) 995 return false; 996 const_cast<RSExportType*>(mPointeeType)->keep(); 997 return true; 998} 999 1000bool RSExportPointerType::equals(const RSExportable *E) const { 1001 CHECK_PARENT_EQUALITY(RSExportType, E); 1002 return (static_cast<const RSExportPointerType*>(E) 1003 ->getPointeeType()->equals(getPointeeType())); 1004} 1005 1006/***************************** RSExportVectorType *****************************/ 1007llvm::StringRef 1008RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) { 1009 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); 1010 1011 if ((ElementType->getTypeClass() != clang::Type::Builtin)) 1012 return llvm::StringRef(); 1013 1014 const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(const clang::BuiltinType, 1015 ElementType); 1016 if ((EVT->getNumElements() < 1) || 1017 (EVT->getNumElements() > 4)) 1018 return llvm::StringRef(); 1019 1020 switch (BT->getKind()) { 1021 // Compiler is smart enough to optimize following *big if branches* since 1022 // they all become "constant comparison" after macro expansion 1023#define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname) \ 1024 case builtin_type: { \ 1025 const char *Name[] = { cname"2", cname"3", cname"4" }; \ 1026 return Name[EVT->getNumElements() - 2]; \ 1027 break; \ 1028 } 1029#include "RSClangBuiltinEnums.inc" 1030 default: { 1031 return llvm::StringRef(); 1032 } 1033 } 1034} 1035 1036RSExportVectorType *RSExportVectorType::Create(RSContext *Context, 1037 const clang::ExtVectorType *EVT, 1038 const llvm::StringRef &TypeName, 1039 DataKind DK, 1040 bool Normalized) { 1041 slangAssert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector); 1042 1043 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); 1044 RSExportPrimitiveType::DataType DT = 1045 RSExportPrimitiveType::GetDataType(Context, ElementType); 1046 1047 if (DT != RSExportPrimitiveType::DataTypeUnknown) 1048 return new RSExportVectorType(Context, 1049 TypeName, 1050 DT, 1051 DK, 1052 Normalized, 1053 EVT->getNumElements()); 1054 else 1055 return NULL; 1056} 1057 1058const llvm::Type *RSExportVectorType::convertToLLVMType() const { 1059 const llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType(); 1060 return llvm::VectorType::get(ElementType, getNumElement()); 1061} 1062 1063union RSType *RSExportVectorType::convertToSpecType() const { 1064 llvm::OwningPtr<union RSType> ST(new union RSType); 1065 1066 RS_TYPE_SET_CLASS(ST, RS_TC_Vector); 1067 RS_VECTOR_TYPE_SET_ELEMENT_TYPE(ST, getType()); 1068 RS_VECTOR_TYPE_SET_VECTOR_SIZE(ST, getNumElement()); 1069 1070 return ST.take(); 1071} 1072 1073bool RSExportVectorType::equals(const RSExportable *E) const { 1074 CHECK_PARENT_EQUALITY(RSExportPrimitiveType, E); 1075 return (static_cast<const RSExportVectorType*>(E)->getNumElement() 1076 == getNumElement()); 1077} 1078 1079/***************************** RSExportMatrixType *****************************/ 1080RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context, 1081 const clang::RecordType *RT, 1082 const llvm::StringRef &TypeName, 1083 unsigned Dim) { 1084 slangAssert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record)); 1085 slangAssert((Dim > 1) && "Invalid dimension of matrix"); 1086 1087 // Check whether the struct rs_matrix is in our expected form (but assume it's 1088 // correct if we're not sure whether it's correct or not) 1089 const clang::RecordDecl* RD = RT->getDecl(); 1090 RD = RD->getDefinition(); 1091 if (RD != NULL) { 1092 clang::Diagnostic *Diags = Context->getDiagnostics(); 1093 const clang::SourceManager *SM = Context->getSourceManager(); 1094 // Find definition, perform further examination 1095 if (RD->field_empty()) { 1096 Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM), 1097 Diags->getCustomDiagID(clang::Diagnostic::Error, 1098 "invalid matrix struct: must have 1 field for saving " 1099 "values: '%0'")) 1100 << RD->getName(); 1101 return NULL; 1102 } 1103 1104 clang::RecordDecl::field_iterator FIT = RD->field_begin(); 1105 const clang::FieldDecl *FD = *FIT; 1106 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD); 1107 if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) { 1108 Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM), 1109 Diags->getCustomDiagID(clang::Diagnostic::Error, 1110 "invalid matrix struct: first field should be an " 1111 "array with constant size: '%0'")) 1112 << RD->getName(); 1113 return NULL; 1114 } 1115 const clang::ConstantArrayType *CAT = 1116 static_cast<const clang::ConstantArrayType *>(FT); 1117 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT); 1118 if ((ElementType == NULL) || 1119 (ElementType->getTypeClass() != clang::Type::Builtin) || 1120 (static_cast<const clang::BuiltinType *>(ElementType)->getKind() 1121 != clang::BuiltinType::Float)) { 1122 Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM), 1123 Diags->getCustomDiagID(clang::Diagnostic::Error, 1124 "invalid matrix struct: first field should be a " 1125 "float array: '%0'")) 1126 << RD->getName(); 1127 return NULL; 1128 } 1129 1130 if (CAT->getSize() != Dim * Dim) { 1131 Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM), 1132 Diags->getCustomDiagID(clang::Diagnostic::Error, 1133 "invalid matrix struct: first field should be an " 1134 "array with size %0: '%1'")) 1135 << Dim * Dim 1136 << RD->getName(); 1137 return NULL; 1138 } 1139 1140 FIT++; 1141 if (FIT != RD->field_end()) { 1142 Diags->Report(clang::FullSourceLoc(RD->getLocation(), *SM), 1143 Diags->getCustomDiagID(clang::Diagnostic::Error, 1144 "invalid matrix struct: must have exactly 1 field: " 1145 "'%0'")) 1146 << RD->getName(); 1147 return NULL; 1148 } 1149 } 1150 1151 return new RSExportMatrixType(Context, TypeName, Dim); 1152} 1153 1154const llvm::Type *RSExportMatrixType::convertToLLVMType() const { 1155 // Construct LLVM type: 1156 // struct { 1157 // float X[mDim * mDim]; 1158 // } 1159 1160 llvm::LLVMContext &C = getRSContext()->getLLVMContext(); 1161 llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C), 1162 mDim * mDim); 1163 return llvm::StructType::get(C, llvm::ArrayRef<const llvm::Type*>(X), false); 1164} 1165 1166union RSType *RSExportMatrixType::convertToSpecType() const { 1167 llvm::OwningPtr<union RSType> ST(new union RSType); 1168 RS_TYPE_SET_CLASS(ST, RS_TC_Matrix); 1169 switch (getDim()) { 1170 case 2: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix2x2); break; 1171 case 3: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix3x3); break; 1172 case 4: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix4x4); break; 1173 default: slangAssert(false && "Matrix type with unsupported dimension."); 1174 } 1175 return ST.take(); 1176} 1177 1178bool RSExportMatrixType::equals(const RSExportable *E) const { 1179 CHECK_PARENT_EQUALITY(RSExportType, E); 1180 return (static_cast<const RSExportMatrixType*>(E)->getDim() == getDim()); 1181} 1182 1183/************************* RSExportConstantArrayType *************************/ 1184RSExportConstantArrayType 1185*RSExportConstantArrayType::Create(RSContext *Context, 1186 const clang::ConstantArrayType *CAT) { 1187 slangAssert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray); 1188 1189 slangAssert((CAT->getSize().getActiveBits() < 32) && "array too large"); 1190 1191 unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue()); 1192 slangAssert((Size > 0) && "Constant array should have size greater than 0"); 1193 1194 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT); 1195 RSExportType *ElementET = RSExportType::Create(Context, ElementType); 1196 1197 if (ElementET == NULL) { 1198 return NULL; 1199 } 1200 1201 return new RSExportConstantArrayType(Context, 1202 ElementET, 1203 Size); 1204} 1205 1206const llvm::Type *RSExportConstantArrayType::convertToLLVMType() const { 1207 return llvm::ArrayType::get(mElementType->getLLVMType(), getSize()); 1208} 1209 1210union RSType *RSExportConstantArrayType::convertToSpecType() const { 1211 llvm::OwningPtr<union RSType> ST(new union RSType); 1212 1213 RS_TYPE_SET_CLASS(ST, RS_TC_ConstantArray); 1214 RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_TYPE( 1215 ST, getElementType()->getSpecType()); 1216 RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_SIZE(ST, getSize()); 1217 1218 if (RS_CONSTANT_ARRAY_TYPE_GET_ELEMENT_TYPE(ST) != NULL) 1219 return ST.take(); 1220 else 1221 return NULL; 1222} 1223 1224bool RSExportConstantArrayType::keep() { 1225 if (!RSExportType::keep()) 1226 return false; 1227 const_cast<RSExportType*>(mElementType)->keep(); 1228 return true; 1229} 1230 1231bool RSExportConstantArrayType::equals(const RSExportable *E) const { 1232 CHECK_PARENT_EQUALITY(RSExportType, E); 1233 const RSExportConstantArrayType *RHS = 1234 static_cast<const RSExportConstantArrayType*>(E); 1235 return ((getSize() == RHS->getSize()) && 1236 (getElementType()->equals(RHS->getElementType()))); 1237} 1238 1239/**************************** RSExportRecordType ****************************/ 1240RSExportRecordType *RSExportRecordType::Create(RSContext *Context, 1241 const clang::RecordType *RT, 1242 const llvm::StringRef &TypeName, 1243 bool mIsArtificial) { 1244 slangAssert(RT != NULL && RT->getTypeClass() == clang::Type::Record); 1245 1246 const clang::RecordDecl *RD = RT->getDecl(); 1247 slangAssert(RD->isStruct()); 1248 1249 RD = RD->getDefinition(); 1250 if (RD == NULL) { 1251 slangAssert(false && "struct is not defined in this module"); 1252 return NULL; 1253 } 1254 1255 // Struct layout construct by clang. We rely on this for obtaining the 1256 // alloc size of a struct and offset of every field in that struct. 1257 const clang::ASTRecordLayout *RL = 1258 &Context->getASTContext().getASTRecordLayout(RD); 1259 slangAssert((RL != NULL) && 1260 "Failed to retrieve the struct layout from Clang."); 1261 1262 RSExportRecordType *ERT = 1263 new RSExportRecordType(Context, 1264 TypeName, 1265 RD->hasAttr<clang::PackedAttr>(), 1266 mIsArtificial, 1267 RL->getSize().getQuantity()); 1268 unsigned int Index = 0; 1269 1270 for (clang::RecordDecl::field_iterator FI = RD->field_begin(), 1271 FE = RD->field_end(); 1272 FI != FE; 1273 FI++, Index++) { 1274 clang::Diagnostic *Diags = Context->getDiagnostics(); 1275 1276 // FIXME: All fields should be primitive type 1277 slangAssert((*FI)->getKind() == clang::Decl::Field); 1278 clang::FieldDecl *FD = *FI; 1279 1280 if (FD->isBitField()) { 1281 delete ERT; 1282 return NULL; 1283 } 1284 1285 // Type 1286 RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD); 1287 1288 if (ET != NULL) { 1289 ERT->mFields.push_back( 1290 new Field(ET, FD->getName(), ERT, 1291 static_cast<size_t>(RL->getFieldOffset(Index) >> 3))); 1292 } else { 1293 Diags->Report(clang::FullSourceLoc(RD->getLocation(), 1294 Diags->getSourceManager()), 1295 Diags->getCustomDiagID(clang::Diagnostic::Error, 1296 "field type cannot be exported: '%0.%1'")) 1297 << RD->getName() 1298 << FD->getName(); 1299 delete ERT; 1300 return NULL; 1301 } 1302 } 1303 1304 return ERT; 1305} 1306 1307const llvm::Type *RSExportRecordType::convertToLLVMType() const { 1308 // Create an opaque type since struct may reference itself recursively. 1309 llvm::PATypeHolder ResultHolder = 1310 llvm::OpaqueType::get(getRSContext()->getLLVMContext()); 1311 setAbstractLLVMType(ResultHolder.get()); 1312 1313 std::vector<const llvm::Type*> FieldTypes; 1314 1315 for (const_field_iterator FI = fields_begin(), FE = fields_end(); 1316 FI != FE; 1317 FI++) { 1318 const Field *F = *FI; 1319 const RSExportType *FET = F->getType(); 1320 1321 FieldTypes.push_back(FET->getLLVMType()); 1322 } 1323 1324 llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(), 1325 FieldTypes, 1326 mIsPacked); 1327 if (ST != NULL) 1328 static_cast<llvm::OpaqueType*>(ResultHolder.get()) 1329 ->refineAbstractTypeTo(ST); 1330 else 1331 return NULL; 1332 return ResultHolder.get(); 1333} 1334 1335union RSType *RSExportRecordType::convertToSpecType() const { 1336 unsigned NumFields = getFields().size(); 1337 unsigned AllocSize = sizeof(union RSType) + 1338 sizeof(struct RSRecordField) * NumFields; 1339 llvm::OwningPtr<union RSType> ST( 1340 reinterpret_cast<union RSType*>(operator new(AllocSize))); 1341 1342 ::memset(ST.get(), 0, AllocSize); 1343 1344 RS_TYPE_SET_CLASS(ST, RS_TC_Record); 1345 RS_RECORD_TYPE_SET_NAME(ST, getName().c_str()); 1346 RS_RECORD_TYPE_SET_NUM_FIELDS(ST, NumFields); 1347 1348 setSpecTypeTemporarily(ST.get()); 1349 1350 unsigned FieldIdx = 0; 1351 for (const_field_iterator FI = fields_begin(), FE = fields_end(); 1352 FI != FE; 1353 FI++, FieldIdx++) { 1354 const Field *F = *FI; 1355 1356 RS_RECORD_TYPE_SET_FIELD_NAME(ST, FieldIdx, F->getName().c_str()); 1357 RS_RECORD_TYPE_SET_FIELD_TYPE(ST, FieldIdx, F->getType()->getSpecType()); 1358 1359 enum RSDataKind DK = RS_DK_User; 1360 if ((F->getType()->getClass() == ExportClassPrimitive) || 1361 (F->getType()->getClass() == ExportClassVector)) { 1362 const RSExportPrimitiveType *EPT = 1363 static_cast<const RSExportPrimitiveType*>(F->getType()); 1364 // enum RSExportPrimitiveType::DataKind is synced with enum RSDataKind in 1365 // slang_rs_type_spec.h 1366 DK = static_cast<enum RSDataKind>(EPT->getKind()); 1367 } 1368 RS_RECORD_TYPE_SET_FIELD_DATA_KIND(ST, FieldIdx, DK); 1369 } 1370 1371 // TODO(slang): Check whether all fields were created normally. 1372 1373 return ST.take(); 1374} 1375 1376bool RSExportRecordType::keep() { 1377 if (!RSExportType::keep()) 1378 return false; 1379 for (std::list<const Field*>::iterator I = mFields.begin(), 1380 E = mFields.end(); 1381 I != E; 1382 I++) { 1383 const_cast<RSExportType*>((*I)->getType())->keep(); 1384 } 1385 return true; 1386} 1387 1388bool RSExportRecordType::equals(const RSExportable *E) const { 1389 CHECK_PARENT_EQUALITY(RSExportType, E); 1390 1391 const RSExportRecordType *ERT = static_cast<const RSExportRecordType*>(E); 1392 1393 if (ERT->getFields().size() != getFields().size()) 1394 return false; 1395 1396 const_field_iterator AI = fields_begin(), BI = ERT->fields_begin(); 1397 1398 for (unsigned i = 0, e = getFields().size(); i != e; i++) { 1399 if (!(*AI)->getType()->equals((*BI)->getType())) 1400 return false; 1401 AI++; 1402 BI++; 1403 } 1404 1405 return true; 1406} 1407 1408} // namespace slang 1409