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