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