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