slang_rs_export_type.cpp revision 2e1dba6c779a0ae55c76d36a3c03553e16725ab7
1#include "slang_rs_export_type.h" 2 3#include <vector> 4 5#include "llvm/Type.h" 6#include "llvm/DerivedTypes.h" 7 8#include "llvm/ADT/StringExtras.h" 9#include "llvm/Target/TargetData.h" 10 11#include "clang/AST/RecordLayout.h" 12 13#include "slang_rs_context.h" 14#include "slang_rs_export_element.h" 15 16using namespace slang; 17 18/****************************** RSExportType ******************************/ 19bool RSExportType::NormalizeType(const clang::Type *&T, 20 llvm::StringRef &TypeName) { 21 llvm::SmallPtrSet<const clang::Type*, 8> SPS = 22 llvm::SmallPtrSet<const clang::Type*, 8>(); 23 24 if ((T = RSExportType::TypeExportable(T, SPS)) == NULL) 25 // TODO(zonr): warn that type not exportable. 26 return false; 27 28 // Get type name 29 TypeName = RSExportType::GetTypeName(T); 30 if (TypeName.empty()) 31 // TODO(zonr): warning that the type is unnamed. 32 return false; 33 34 return true; 35} 36 37const clang::Type 38*RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) { 39 if (DD) { 40 clang::QualType T; 41 if (DD->getTypeSourceInfo()) 42 T = DD->getTypeSourceInfo()->getType(); 43 else 44 T = DD->getType(); 45 46 if (T.isNull()) 47 return NULL; 48 else 49 return T.getTypePtr(); 50 } 51 return NULL; 52} 53 54llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) { 55 T = GET_CANONICAL_TYPE(T); 56 if (T == NULL) 57 return llvm::StringRef(); 58 59 switch (T->getTypeClass()) { 60 case clang::Type::Builtin: { 61 const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T); 62 63 switch (BT->getKind()) { 64 // Compiler is smart enough to optimize following *big if branches* 65 // since they all become "constant comparison" after macro expansion 66#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ 67 case builtin_type: { \ 68 if (type == RSExportPrimitiveType::DataTypeFloat32) \ 69 return "float"; \ 70 else if (type == RSExportPrimitiveType::DataTypeFloat64) \ 71 return "double"; \ 72 else if (type == RSExportPrimitiveType::DataTypeUnsigned8) \ 73 return "uchar"; \ 74 else if (type == RSExportPrimitiveType::DataTypeUnsigned16) \ 75 return "ushort"; \ 76 else if (type == RSExportPrimitiveType::DataTypeUnsigned32) \ 77 return "uint"; \ 78 else if (type == RSExportPrimitiveType::DataTypeSigned8) \ 79 return "char"; \ 80 else if (type == RSExportPrimitiveType::DataTypeSigned16) \ 81 return "short"; \ 82 else if (type == RSExportPrimitiveType::DataTypeSigned32) \ 83 return "int"; \ 84 else if (type == RSExportPrimitiveType::DataTypeSigned64) \ 85 return "long"; \ 86 else if (type == RSExportPrimitiveType::DataTypeBoolean) \ 87 return "bool"; \ 88 else \ 89 assert(false && "Unknow data type of supported builtin"); \ 90 break; \ 91 } 92#include "slang_rs_export_type_support.inc" 93 94 default: { 95 assert(false && "Unknown data type of the builtin"); 96 break; 97 } 98 } 99 break; 100 } 101 case clang::Type::Record: { 102 const clang::RecordDecl *RD = T->getAsStructureType()->getDecl(); 103 llvm::StringRef Name = RD->getName(); 104 if (Name.empty()) { 105 if (RD->getTypedefForAnonDecl() != NULL) 106 Name = RD->getTypedefForAnonDecl()->getName(); 107 108 if (Name.empty()) 109 // Try to find a name from redeclaration (i.e. typedef) 110 for (clang::TagDecl::redecl_iterator RI = RD->redecls_begin(), 111 RE = RD->redecls_end(); 112 RI != RE; 113 RI++) { 114 assert(*RI != NULL && "cannot be NULL object"); 115 116 Name = (*RI)->getName(); 117 if (!Name.empty()) 118 break; 119 } 120 } 121 return Name; 122 } 123 case clang::Type::Pointer: { 124 // "*" plus pointee name 125 const clang::Type *PT = GET_POINTEE_TYPE(T); 126 llvm::StringRef PointeeName; 127 if (NormalizeType(PT, PointeeName)) { 128 char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ]; 129 Name[0] = '*'; 130 memcpy(Name + 1, PointeeName.data(), PointeeName.size()); 131 Name[PointeeName.size() + 1] = '\0'; 132 return Name; 133 } 134 break; 135 } 136 case clang::Type::ExtVector: { 137 const clang::ExtVectorType *EVT = 138 UNSAFE_CAST_TYPE(clang::ExtVectorType, T); 139 return RSExportVectorType::GetTypeName(EVT); 140 break; 141 } 142 case clang::Type::ConstantArray : { 143 // Construct name for a constant array is too complicated. 144 return DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE; 145 } 146 default: { 147 break; 148 } 149 } 150 151 return llvm::StringRef(); 152} 153 154const clang::Type *RSExportType::TypeExportable( 155 const clang::Type *T, 156 llvm::SmallPtrSet<const clang::Type*, 8>& SPS) { 157 // Normalize first 158 if ((T = GET_CANONICAL_TYPE(T)) == NULL) 159 return NULL; 160 161 if (SPS.count(T)) 162 return T; 163 164 switch (T->getTypeClass()) { 165 case clang::Type::Builtin: { 166 const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T); 167 168 switch (BT->getKind()) { 169#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ 170 case builtin_type: 171#include "slang_rs_export_type_support.inc" 172 { 173 return T; 174 } 175 default: { 176 return NULL; 177 } 178 } 179 // Never be here 180 } 181 case clang::Type::Record: { 182 if (RSExportPrimitiveType::GetRSObjectType(T) != 183 RSExportPrimitiveType::DataTypeUnknown) 184 return T; // RS object type, no further checks are needed 185 186 // Check internal struct 187 const clang::RecordDecl *RD = T->getAsStructureType()->getDecl(); 188 if (RD != NULL) 189 RD = RD->getDefinition(); 190 191 // Fast check 192 if (RD->hasFlexibleArrayMember() || RD->hasObjectMember()) 193 return NULL; 194 195 // Insert myself into checking set 196 SPS.insert(T); 197 198 // Check all element 199 for (clang::RecordDecl::field_iterator FI = RD->field_begin(), 200 FE = RD->field_end(); 201 FI != FE; 202 FI++) { 203 const clang::FieldDecl *FD = *FI; 204 const clang::Type *FT = GetTypeOfDecl(FD); 205 FT = GET_CANONICAL_TYPE(FT); 206 207 if (!TypeExportable(FT, SPS)) { 208 fprintf(stderr, "Field `%s' in Record `%s' contains unsupported " 209 "type\n", FD->getNameAsString().c_str(), 210 RD->getNameAsString().c_str()); 211 FT->dump(); 212 return NULL; 213 } 214 } 215 216 return T; 217 } 218 case clang::Type::Pointer: { 219 const clang::PointerType *PT = UNSAFE_CAST_TYPE(clang::PointerType, T); 220 const clang::Type *PointeeType = GET_POINTEE_TYPE(PT); 221 222 if (PointeeType->getTypeClass() == clang::Type::Pointer) 223 return T; 224 // We don't support pointer with array-type pointee or unsupported pointee 225 // type 226 if (PointeeType->isArrayType() || 227 (TypeExportable(PointeeType, SPS) == NULL) ) 228 return NULL; 229 else 230 return T; 231 } 232 case clang::Type::ExtVector: { 233 const clang::ExtVectorType *EVT = 234 UNSAFE_CAST_TYPE(clang::ExtVectorType, T); 235 // Only vector with size 2, 3 and 4 are supported. 236 if (EVT->getNumElements() < 2 || EVT->getNumElements() > 4) 237 return NULL; 238 239 // Check base element type 240 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); 241 242 if ((ElementType->getTypeClass() != clang::Type::Builtin) || 243 (TypeExportable(ElementType, SPS) == NULL)) 244 return NULL; 245 else 246 return T; 247 } 248 case clang::Type::ConstantArray: { 249 const clang::ConstantArrayType *CAT = 250 UNSAFE_CAST_TYPE(clang::ConstantArrayType, T); 251 252 // Check size 253 if (CAT->getSize().getActiveBits() > 32) { 254 fprintf(stderr, "RSExportConstantArrayType::Create : array with too " 255 "large size (> 2^32).\n"); 256 return NULL; 257 } 258 // Check element type 259 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT); 260 if (ElementType->isArrayType()) { 261 fprintf(stderr, "RSExportType::TypeExportable : constant array with 2 " 262 "or higher dimension of constant is not supported.\n"); 263 return NULL; 264 } 265 if (TypeExportable(ElementType, SPS) == NULL) 266 return NULL; 267 else 268 return T; 269 } 270 default: { 271 return NULL; 272 } 273 } 274} 275 276RSExportType *RSExportType::Create(RSContext *Context, 277 const clang::Type *T, 278 const llvm::StringRef &TypeName) { 279 // Lookup the context to see whether the type was processed before. 280 // Newly created RSExportType will insert into context 281 // in RSExportType::RSExportType() 282 RSContext::export_type_iterator ETI = Context->findExportType(TypeName); 283 284 if (ETI != Context->export_types_end()) 285 return ETI->second; 286 287 RSExportType *ET = NULL; 288 switch (T->getTypeClass()) { 289 case clang::Type::Record: { 290 RSExportPrimitiveType::DataType dt = 291 RSExportPrimitiveType::GetRSObjectType(TypeName); 292 switch (dt) { 293 case RSExportPrimitiveType::DataTypeUnknown: { 294 // User-defined types 295 ET = RSExportRecordType::Create(Context, 296 T->getAsStructureType(), 297 TypeName); 298 break; 299 } 300 case RSExportPrimitiveType::DataTypeRSMatrix2x2: { 301 // 2 x 2 Matrix type 302 ET = RSExportMatrixType::Create(Context, 303 T->getAsStructureType(), 304 TypeName, 305 2); 306 break; 307 } 308 case RSExportPrimitiveType::DataTypeRSMatrix3x3: { 309 // 3 x 3 Matrix type 310 ET = RSExportMatrixType::Create(Context, 311 T->getAsStructureType(), 312 TypeName, 313 3); 314 break; 315 } 316 case RSExportPrimitiveType::DataTypeRSMatrix4x4: { 317 // 4 x 4 Matrix type 318 ET = RSExportMatrixType::Create(Context, 319 T->getAsStructureType(), 320 TypeName, 321 4); 322 break; 323 } 324 default: { 325 // Others are primitive types 326 ET = RSExportPrimitiveType::Create(Context, T, TypeName); 327 break; 328 } 329 } 330 break; 331 } 332 case clang::Type::Builtin: { 333 ET = RSExportPrimitiveType::Create(Context, T, TypeName); 334 break; 335 } 336 case clang::Type::Pointer: { 337 ET = RSExportPointerType::Create(Context, 338 UNSAFE_CAST_TYPE(clang::PointerType, T), 339 TypeName); 340 // FIXME: free the name (allocated in RSExportType::GetTypeName) 341 delete [] TypeName.data(); 342 break; 343 } 344 case clang::Type::ExtVector: { 345 ET = RSExportVectorType::Create(Context, 346 UNSAFE_CAST_TYPE(clang::ExtVectorType, T), 347 TypeName); 348 break; 349 } 350 case clang::Type::ConstantArray: { 351 ET = RSExportConstantArrayType::Create( 352 Context, 353 UNSAFE_CAST_TYPE(clang::ConstantArrayType, T)); 354 break; 355 } 356 default: { 357 // TODO(zonr): warn that type is not exportable. 358 fprintf(stderr, 359 "RSExportType::Create : type '%s' is not exportable\n", 360 T->getTypeClassName()); 361 break; 362 } 363 } 364 365 return ET; 366} 367 368RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) { 369 llvm::StringRef TypeName; 370 if (NormalizeType(T, TypeName)) 371 return Create(Context, T, TypeName); 372 else 373 return NULL; 374} 375 376RSExportType *RSExportType::CreateFromDecl(RSContext *Context, 377 const clang::VarDecl *VD) { 378 return RSExportType::Create(Context, GetTypeOfDecl(VD)); 379} 380 381size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) { 382 return ET->getRSContext()->getTargetData()->getTypeStoreSize( 383 ET->getLLVMType()); 384} 385 386size_t RSExportType::GetTypeAllocSize(const RSExportType *ET) { 387 if (ET->getClass() == RSExportType::ExportClassRecord) 388 return static_cast<const RSExportRecordType*>(ET)->getAllocSize(); 389 else 390 return ET->getRSContext()->getTargetData()->getTypeAllocSize( 391 ET->getLLVMType()); 392} 393 394RSExportType::RSExportType(RSContext *Context, const llvm::StringRef &Name) 395 : mContext(Context), 396 // Make a copy on Name since memory stored @Name is either allocated in 397 // ASTContext or allocated in GetTypeName which will be destroyed later. 398 mName(Name.data(), Name.size()), 399 mLLVMType(NULL) { 400 // Don't cache the type whose name start with '<'. Those type failed to 401 // get their name since constructing their name in GetTypeName() requiring 402 // complicated work. 403 if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX)) 404 // TODO(zonr): Need to check whether the insertion is successful or not. 405 Context->insertExportType(llvm::StringRef(Name), this); 406 return; 407} 408 409/************************** RSExportPrimitiveType **************************/ 410RSExportPrimitiveType::RSObjectTypeMapTy 411*RSExportPrimitiveType::RSObjectTypeMap = NULL; 412 413llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL; 414 415bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) { 416 if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin)) 417 return true; 418 else 419 return false; 420} 421 422RSExportPrimitiveType::DataType 423RSExportPrimitiveType::GetRSObjectType(const llvm::StringRef &TypeName) { 424 if (TypeName.empty()) 425 return DataTypeUnknown; 426 427 if (RSObjectTypeMap == NULL) { 428 RSObjectTypeMap = new RSObjectTypeMapTy(16); 429 430#define USE_ELEMENT_DATA_TYPE 431#define DEF_RS_OBJECT_TYPE(type, name) \ 432 RSObjectTypeMap->GetOrCreateValue(name, GET_ELEMENT_DATA_TYPE(type)); 433#include "slang_rs_export_element_support.inc" 434 } 435 436 RSObjectTypeMapTy::const_iterator I = RSObjectTypeMap->find(TypeName); 437 if (I == RSObjectTypeMap->end()) 438 return DataTypeUnknown; 439 else 440 return I->getValue(); 441} 442 443RSExportPrimitiveType::DataType 444RSExportPrimitiveType::GetRSObjectType(const clang::Type *T) { 445 T = GET_CANONICAL_TYPE(T); 446 if ((T == NULL) || (T->getTypeClass() != clang::Type::Record)) 447 return DataTypeUnknown; 448 449 return GetRSObjectType( RSExportType::GetTypeName(T) ); 450} 451 452const size_t 453RSExportPrimitiveType::SizeOfDataTypeInBits[ 454 RSExportPrimitiveType::DataTypeMax + 1] = { 455 16, // DataTypeFloat16 456 32, // DataTypeFloat32 457 64, // DataTypeFloat64 458 8, // DataTypeSigned8 459 16, // DataTypeSigned16 460 32, // DataTypeSigned32 461 64, // DataTypeSigned64 462 8, // DataTypeUnsigned8 463 16, // DataTypeUnsigned16 464 32, // DataTypeUnsigned32 465 64, // DataTypeUnSigned64 466 1, // DataTypeBoolean 467 468 16, // DataTypeUnsigned565 469 16, // DataTypeUnsigned5551 470 16, // DataTypeUnsigned4444 471 472 128, // DataTypeRSMatrix2x2 473 288, // DataTypeRSMatrix3x3 474 512, // DataTypeRSMatrix4x4 475 476 32, // DataTypeRSElement 477 32, // DataTypeRSType 478 32, // DataTypeRSAllocation 479 32, // DataTypeRSSampler 480 32, // DataTypeRSScript 481 32, // DataTypeRSMesh 482 32, // DataTypeRSProgramFragment 483 32, // DataTypeRSProgramVertex 484 32, // DataTypeRSProgramRaster 485 32, // DataTypeRSProgramStore 486 32, // DataTypeRSFont 487 0 488}; 489 490size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) { 491 assert(((EPT->getType() >= DataTypeFloat32) && 492 (EPT->getType() < DataTypeMax)) && 493 "RSExportPrimitiveType::GetSizeInBits : unknown data type"); 494 return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ]; 495} 496 497RSExportPrimitiveType::DataType 498RSExportPrimitiveType::GetDataType(const clang::Type *T) { 499 if (T == NULL) 500 return DataTypeUnknown; 501 502 switch (T->getTypeClass()) { 503 case clang::Type::Builtin: { 504 const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T); 505 switch (BT->getKind()) { 506#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ 507 case builtin_type: { \ 508 return type; \ 509 break; \ 510 } 511#include "slang_rs_export_type_support.inc" 512 513 // The size of types Long, ULong and WChar depend on platform so we 514 // abandon the support to them. Type of its size exceeds 32 bits (e.g. 515 // int64_t, double, etc.): no support 516 517 default: { 518 // TODO(zonr): warn that the type is unsupported 519 fprintf(stderr, "RSExportPrimitiveType::GetDataType : built-in type " 520 "has no corresponding data type for built-in type"); 521 break; 522 } 523 } 524 break; 525 } 526 527 case clang::Type::Record: { 528 // must be RS object type 529 return RSExportPrimitiveType::GetRSObjectType(T); 530 break; 531 } 532 533 default: { 534 fprintf(stderr, "RSExportPrimitiveType::GetDataType : type '%s' is not " 535 "supported primitive type", T->getTypeClassName()); 536 break; 537 } 538 } 539 540 return DataTypeUnknown; 541} 542 543RSExportPrimitiveType 544*RSExportPrimitiveType::Create(RSContext *Context, 545 const clang::Type *T, 546 const llvm::StringRef &TypeName, 547 DataKind DK, 548 bool Normalized) { 549 DataType DT = GetDataType(T); 550 551 if ((DT == DataTypeUnknown) || TypeName.empty()) 552 return NULL; 553 else 554 return new RSExportPrimitiveType(Context, TypeName, DT, DK, Normalized); 555} 556 557RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context, 558 const clang::Type *T, 559 DataKind DK) { 560 llvm::StringRef TypeName; 561 if (RSExportType::NormalizeType(T, TypeName) && IsPrimitiveType(T)) 562 return Create(Context, T, TypeName, DK); 563 else 564 return NULL; 565} 566 567RSExportType::ExportClass RSExportPrimitiveType::getClass() const { 568 return RSExportType::ExportClassPrimitive; 569} 570 571const llvm::Type *RSExportPrimitiveType::convertToLLVMType() const { 572 llvm::LLVMContext &C = getRSContext()->getLLVMContext(); 573 574 if (isRSObjectType()) { 575 // struct { 576 // int *p; 577 // } __attribute__((packed, aligned(pointer_size))) 578 // 579 // which is 580 // 581 // <{ [1 x i32] }> in LLVM 582 // 583 if (RSObjectLLVMType == NULL) { 584 std::vector<const llvm::Type *> Elements; 585 Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1)); 586 RSObjectLLVMType = llvm::StructType::get(C, Elements, true); 587 } 588 return RSObjectLLVMType; 589 } 590 591 switch (mType) { 592 case DataTypeFloat32: { 593 return llvm::Type::getFloatTy(C); 594 break; 595 } 596 case DataTypeFloat64: { 597 return llvm::Type::getDoubleTy(C); 598 break; 599 } 600 case DataTypeBoolean: { 601 return llvm::Type::getInt1Ty(C); 602 break; 603 } 604 case DataTypeSigned8: 605 case DataTypeUnsigned8: { 606 return llvm::Type::getInt8Ty(C); 607 break; 608 } 609 case DataTypeSigned16: 610 case DataTypeUnsigned16: 611 case DataTypeUnsigned565: 612 case DataTypeUnsigned5551: 613 case DataTypeUnsigned4444: { 614 return llvm::Type::getInt16Ty(C); 615 break; 616 } 617 case DataTypeSigned32: 618 case DataTypeUnsigned32: { 619 return llvm::Type::getInt32Ty(C); 620 break; 621 } 622 case DataTypeSigned64: { 623 // case DataTypeUnsigned64: 624 return llvm::Type::getInt64Ty(C); 625 break; 626 } 627 default: { 628 assert(false && "Unknown data type"); 629 } 630 } 631 632 return NULL; 633} 634 635/**************************** RSExportPointerType ****************************/ 636 637const clang::Type *RSExportPointerType::IntegerType = NULL; 638 639RSExportPointerType 640*RSExportPointerType::Create(RSContext *Context, 641 const clang::PointerType *PT, 642 const llvm::StringRef &TypeName) { 643 const clang::Type *PointeeType = GET_POINTEE_TYPE(PT); 644 const RSExportType *PointeeET; 645 646 if (PointeeType->getTypeClass() != clang::Type::Pointer) { 647 PointeeET = RSExportType::Create(Context, PointeeType); 648 } else { 649 // Double or higher dimension of pointer, export as int* 650 assert(IntegerType != NULL && "Built-in integer type is not set"); 651 PointeeET = RSExportPrimitiveType::Create(Context, IntegerType); 652 } 653 654 if (PointeeET == NULL) { 655 fprintf(stderr, "Failed to create type for pointee"); 656 return NULL; 657 } 658 659 return new RSExportPointerType(Context, TypeName, PointeeET); 660} 661 662RSExportType::ExportClass RSExportPointerType::getClass() const { 663 return RSExportType::ExportClassPointer; 664} 665 666const llvm::Type *RSExportPointerType::convertToLLVMType() const { 667 const llvm::Type *PointeeType = mPointeeType->getLLVMType(); 668 return llvm::PointerType::getUnqual(PointeeType); 669} 670 671/***************************** RSExportVectorType *****************************/ 672const char* RSExportVectorType::VectorTypeNameStore[][3] = { 673 /* 0 */ { "char2", "char3", "char4" }, 674 /* 1 */ { "uchar2", "uchar3", "uchar4" }, 675 /* 2 */ { "short2", "short3", "short4" }, 676 /* 3 */ { "ushort2", "ushort3", "ushort4" }, 677 /* 4 */ { "int2", "int3", "int4" }, 678 /* 5 */ { "uint2", "uint3", "uint4" }, 679 /* 6 */ { "float2", "float3", "float4" }, 680 /* 7 */ { "double2", "double3", "double4" }, 681 /* 8 */ { "long2", "long3", "long4" }, 682}; 683 684llvm::StringRef 685RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) { 686 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); 687 688 if ((ElementType->getTypeClass() != clang::Type::Builtin)) 689 return llvm::StringRef(); 690 691 const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, 692 ElementType); 693 const char **BaseElement = NULL; 694 695 switch (BT->getKind()) { 696 // Compiler is smart enough to optimize following *big if branches* since 697 // they all become "constant comparison" after macro expansion 698#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ 699 case builtin_type: { \ 700 if (type == RSExportPrimitiveType::DataTypeSigned8) \ 701 BaseElement = VectorTypeNameStore[0]; \ 702 else if (type == RSExportPrimitiveType::DataTypeUnsigned8) \ 703 BaseElement = VectorTypeNameStore[1]; \ 704 else if (type == RSExportPrimitiveType::DataTypeSigned16) \ 705 BaseElement = VectorTypeNameStore[2]; \ 706 else if (type == RSExportPrimitiveType::DataTypeUnsigned16) \ 707 BaseElement = VectorTypeNameStore[3]; \ 708 else if (type == RSExportPrimitiveType::DataTypeSigned32) \ 709 BaseElement = VectorTypeNameStore[4]; \ 710 else if (type == RSExportPrimitiveType::DataTypeUnsigned32) \ 711 BaseElement = VectorTypeNameStore[5]; \ 712 else if (type == RSExportPrimitiveType::DataTypeFloat32) \ 713 BaseElement = VectorTypeNameStore[6]; \ 714 else if (type == RSExportPrimitiveType::DataTypeFloat64) \ 715 BaseElement = VectorTypeNameStore[7]; \ 716 else if (type == RSExportPrimitiveType::DataTypeSigned64) \ 717 BaseElement = VectorTypeNameStore[8]; \ 718 else if (type == RSExportPrimitiveType::DataTypeBoolean) \ 719 BaseElement = VectorTypeNameStore[0]; \ 720 break; \ 721 } 722#include "slang_rs_export_type_support.inc" 723 default: { 724 return llvm::StringRef(); 725 } 726 } 727 728 if ((BaseElement != NULL) && 729 (EVT->getNumElements() > 1) && 730 (EVT->getNumElements() <= 4)) 731 return BaseElement[EVT->getNumElements() - 2]; 732 else 733 return llvm::StringRef(); 734} 735 736RSExportVectorType *RSExportVectorType::Create(RSContext *Context, 737 const clang::ExtVectorType *EVT, 738 const llvm::StringRef &TypeName, 739 DataKind DK, 740 bool Normalized) { 741 assert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector); 742 743 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); 744 RSExportPrimitiveType::DataType DT = 745 RSExportPrimitiveType::GetDataType(ElementType); 746 747 if (DT != RSExportPrimitiveType::DataTypeUnknown) 748 return new RSExportVectorType(Context, 749 TypeName, 750 DT, 751 DK, 752 Normalized, 753 EVT->getNumElements()); 754 else 755 fprintf(stderr, "RSExportVectorType::Create : unsupported base element " 756 "type\n"); 757 return NULL; 758} 759 760RSExportType::ExportClass RSExportVectorType::getClass() const { 761 return RSExportType::ExportClassVector; 762} 763 764const llvm::Type *RSExportVectorType::convertToLLVMType() const { 765 const llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType(); 766 return llvm::VectorType::get(ElementType, getNumElement()); 767} 768 769/***************************** RSExportMatrixType *****************************/ 770RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context, 771 const clang::RecordType *RT, 772 const llvm::StringRef &TypeName, 773 unsigned Dim) { 774 assert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record)); 775 assert((Dim > 1) && "Invalid dimension of matrix"); 776 777 // Check whether the struct rs_matrix is in our expected form (but assume it's 778 // correct if we're not sure whether it's correct or not) 779 const clang::RecordDecl* RD = RT->getDecl(); 780 RD = RD->getDefinition(); 781 if (RD != NULL) { 782 // Find definition, perform further examination 783 if (RD->field_empty()) { 784 fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: " 785 "must have 1 field for saving values", TypeName.data()); 786 return NULL; 787 } 788 789 clang::RecordDecl::field_iterator FIT = RD->field_begin(); 790 const clang::FieldDecl *FD = *FIT; 791 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD); 792 if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) { 793 fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: " 794 "first field should be an array with constant size", 795 TypeName.data()); 796 return NULL; 797 } 798 const clang::ConstantArrayType *CAT = 799 static_cast<const clang::ConstantArrayType *>(FT); 800 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT); 801 if ((ElementType == NULL) || 802 (ElementType->getTypeClass() != clang::Type::Builtin) || 803 (static_cast<const clang::BuiltinType *>(ElementType)->getKind() 804 != clang::BuiltinType::Float)) { 805 fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: " 806 "first field should be a float array", TypeName.data()); 807 return NULL; 808 } 809 810 if (CAT->getSize() != Dim * Dim) { 811 fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: " 812 "first field should be an array with size %d", 813 TypeName.data(), Dim * Dim); 814 return NULL; 815 } 816 817 FIT++; 818 if (FIT != RD->field_end()) { 819 fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: " 820 "must have exactly 1 field", TypeName.data()); 821 return NULL; 822 } 823 } 824 825 return new RSExportMatrixType(Context, TypeName, Dim); 826} 827 828RSExportType::ExportClass RSExportMatrixType::getClass() const { 829 return RSExportType::ExportClassMatrix; 830} 831 832const llvm::Type *RSExportMatrixType::convertToLLVMType() const { 833 // Construct LLVM type: 834 // struct { 835 // float X[mDim * mDim]; 836 // } 837 838 llvm::LLVMContext &C = getRSContext()->getLLVMContext(); 839 llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C), 840 mDim * mDim); 841 return llvm::StructType::get(C, X, NULL); 842} 843 844/************************* RSExportConstantArrayType *************************/ 845RSExportConstantArrayType 846*RSExportConstantArrayType::Create(RSContext *Context, 847 const clang::ConstantArrayType *CAT) { 848 assert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray); 849 850 assert((CAT->getSize().getActiveBits() < 32) && "array too large"); 851 852 unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue()); 853 assert((Size > 0) && "Constant array should have size greater than 0"); 854 855 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT); 856 RSExportType *ElementET = RSExportType::Create(Context, ElementType); 857 858 if (ElementET == NULL) { 859 fprintf(stderr, "RSExportConstantArrayType::Create : failed to create " 860 "RSExportType for array element.\n"); 861 return NULL; 862 } 863 864 return new RSExportConstantArrayType(Context, 865 ElementET, 866 Size); 867} 868 869RSExportType::ExportClass RSExportConstantArrayType::getClass() const { 870 return RSExportType::ExportClassConstantArray; 871} 872 873const llvm::Type *RSExportConstantArrayType::convertToLLVMType() const { 874 return llvm::ArrayType::get(mElementType->getLLVMType(), getSize()); 875} 876 877/**************************** RSExportRecordType ****************************/ 878RSExportRecordType *RSExportRecordType::Create(RSContext *Context, 879 const clang::RecordType *RT, 880 const llvm::StringRef &TypeName, 881 bool mIsArtificial) { 882 assert(RT != NULL && RT->getTypeClass() == clang::Type::Record); 883 884 const clang::RecordDecl *RD = RT->getDecl(); 885 assert(RD->isStruct()); 886 887 RD = RD->getDefinition(); 888 if (RD == NULL) { 889 // TODO(zonr): warn that actual struct definition isn't declared in this 890 // moudle. 891 fprintf(stderr, "RSExportRecordType::Create : this struct is not defined " 892 "in this module."); 893 return NULL; 894 } 895 896 // Struct layout construct by clang. We rely on this for obtaining the 897 // alloc size of a struct and offset of every field in that struct. 898 const clang::ASTRecordLayout *RL = 899 &Context->getASTContext()->getASTRecordLayout(RD); 900 assert((RL != NULL) && "Failed to retrieve the struct layout from Clang."); 901 902 RSExportRecordType *ERT = 903 new RSExportRecordType(Context, 904 TypeName, 905 RD->hasAttr<clang::PackedAttr>(), 906 mIsArtificial, 907 (RL->getSize() >> 3)); 908 unsigned int Index = 0; 909 910 for (clang::RecordDecl::field_iterator FI = RD->field_begin(), 911 FE = RD->field_end(); 912 FI != FE; 913 FI++, Index++) { 914#define FAILED_CREATE_FIELD(err) do { \ 915 if (*err) \ 916 fprintf(stderr, \ 917 "RSExportRecordType::Create : failed to create field (%s)\n", \ 918 err); \ 919 delete ERT; \ 920 return NULL; \ 921 } while (false) 922 923 // FIXME: All fields should be primitive type 924 assert((*FI)->getKind() == clang::Decl::Field); 925 clang::FieldDecl *FD = *FI; 926 927 // We don't support bit field 928 // 929 // TODO(zonr): allow bitfield with size 8, 16, 32 930 if (FD->isBitField()) 931 FAILED_CREATE_FIELD("bit field is not supported"); 932 933 // Type 934 RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD); 935 936 if (ET != NULL) 937 ERT->mFields.push_back( 938 new Field(ET, FD->getName(), ERT, 939 static_cast<size_t>(RL->getFieldOffset(Index) >> 3))); 940 else 941 FAILED_CREATE_FIELD(FD->getName().str().c_str()); 942#undef FAILED_CREATE_FIELD 943 } 944 945 return ERT; 946} 947 948RSExportType::ExportClass RSExportRecordType::getClass() const { 949 return RSExportType::ExportClassRecord; 950} 951 952const llvm::Type *RSExportRecordType::convertToLLVMType() const { 953 std::vector<const llvm::Type*> FieldTypes; 954 955 for (const_field_iterator FI = fields_begin(), 956 FE = fields_end(); 957 FI != FE; 958 FI++) { 959 const Field *F = *FI; 960 const RSExportType *FET = F->getType(); 961 962 FieldTypes.push_back(FET->getLLVMType()); 963 } 964 965 return llvm::StructType::get(getRSContext()->getLLVMContext(), 966 FieldTypes, 967 mIsPacked); 968} 969