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