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