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