1a7dea167SDimitry Andric //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "Program.h" 10a7dea167SDimitry Andric #include "Context.h" 11a7dea167SDimitry Andric #include "Function.h" 1206c3fb27SDimitry Andric #include "Integral.h" 13a7dea167SDimitry Andric #include "Opcode.h" 14a7dea167SDimitry Andric #include "PrimType.h" 15a7dea167SDimitry Andric #include "clang/AST/Decl.h" 16a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h" 17a7dea167SDimitry Andric 18a7dea167SDimitry Andric using namespace clang; 19a7dea167SDimitry Andric using namespace clang::interp; 20a7dea167SDimitry Andric 21349cc55cSDimitry Andric unsigned Program::getOrCreateNativePointer(const void *Ptr) { 22349cc55cSDimitry Andric auto It = NativePointerIndices.find(Ptr); 23349cc55cSDimitry Andric if (It != NativePointerIndices.end()) 24349cc55cSDimitry Andric return It->second; 25349cc55cSDimitry Andric 26349cc55cSDimitry Andric unsigned Idx = NativePointers.size(); 27349cc55cSDimitry Andric NativePointers.push_back(Ptr); 28349cc55cSDimitry Andric NativePointerIndices[Ptr] = Idx; 29349cc55cSDimitry Andric return Idx; 30349cc55cSDimitry Andric } 31349cc55cSDimitry Andric 32349cc55cSDimitry Andric const void *Program::getNativePointer(unsigned Idx) { 33349cc55cSDimitry Andric return NativePointers[Idx]; 34349cc55cSDimitry Andric } 35349cc55cSDimitry Andric 36a7dea167SDimitry Andric unsigned Program::createGlobalString(const StringLiteral *S) { 37a7dea167SDimitry Andric const size_t CharWidth = S->getCharByteWidth(); 38a7dea167SDimitry Andric const size_t BitWidth = CharWidth * Ctx.getCharBit(); 39a7dea167SDimitry Andric 40a7dea167SDimitry Andric PrimType CharType; 41a7dea167SDimitry Andric switch (CharWidth) { 42a7dea167SDimitry Andric case 1: 43a7dea167SDimitry Andric CharType = PT_Sint8; 44a7dea167SDimitry Andric break; 45a7dea167SDimitry Andric case 2: 46a7dea167SDimitry Andric CharType = PT_Uint16; 47a7dea167SDimitry Andric break; 48a7dea167SDimitry Andric case 4: 49a7dea167SDimitry Andric CharType = PT_Uint32; 50a7dea167SDimitry Andric break; 51a7dea167SDimitry Andric default: 52a7dea167SDimitry Andric llvm_unreachable("unsupported character width"); 53a7dea167SDimitry Andric } 54a7dea167SDimitry Andric 55a7dea167SDimitry Andric // Create a descriptor for the string. 56bdd1243dSDimitry Andric Descriptor *Desc = 57*0fca6ea1SDimitry Andric allocateDescriptor(S, CharType, Descriptor::GlobalMD, S->getLength() + 1, 58a7dea167SDimitry Andric /*isConst=*/true, 59a7dea167SDimitry Andric /*isTemporary=*/false, 60a7dea167SDimitry Andric /*isMutable=*/false); 61a7dea167SDimitry Andric 62a7dea167SDimitry Andric // Allocate storage for the string. 63a7dea167SDimitry Andric // The byte length does not include the null terminator. 64a7dea167SDimitry Andric unsigned I = Globals.size(); 65a7dea167SDimitry Andric unsigned Sz = Desc->getAllocSize(); 66*0fca6ea1SDimitry Andric auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true, 67a7dea167SDimitry Andric /*isExtern=*/false); 68bdd1243dSDimitry Andric G->block()->invokeCtor(); 69*0fca6ea1SDimitry Andric 70*0fca6ea1SDimitry Andric new (G->block()->rawData()) InlineDescriptor(Desc); 71a7dea167SDimitry Andric Globals.push_back(G); 72a7dea167SDimitry Andric 73a7dea167SDimitry Andric // Construct the string in storage. 74a7dea167SDimitry Andric const Pointer Ptr(G->block()); 75a7dea167SDimitry Andric for (unsigned I = 0, N = S->getLength(); I <= N; ++I) { 76a7dea167SDimitry Andric Pointer Field = Ptr.atIndex(I).narrow(); 77a7dea167SDimitry Andric const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I); 78a7dea167SDimitry Andric switch (CharType) { 79a7dea167SDimitry Andric case PT_Sint8: { 80a7dea167SDimitry Andric using T = PrimConv<PT_Sint8>::T; 81a7dea167SDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth); 82*0fca6ea1SDimitry Andric Field.initialize(); 83a7dea167SDimitry Andric break; 84a7dea167SDimitry Andric } 85a7dea167SDimitry Andric case PT_Uint16: { 86a7dea167SDimitry Andric using T = PrimConv<PT_Uint16>::T; 87a7dea167SDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth); 88*0fca6ea1SDimitry Andric Field.initialize(); 89a7dea167SDimitry Andric break; 90a7dea167SDimitry Andric } 91a7dea167SDimitry Andric case PT_Uint32: { 92a7dea167SDimitry Andric using T = PrimConv<PT_Uint32>::T; 93a7dea167SDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth); 94*0fca6ea1SDimitry Andric Field.initialize(); 95a7dea167SDimitry Andric break; 96a7dea167SDimitry Andric } 97a7dea167SDimitry Andric default: 98a7dea167SDimitry Andric llvm_unreachable("unsupported character type"); 99a7dea167SDimitry Andric } 100a7dea167SDimitry Andric } 101a7dea167SDimitry Andric return I; 102a7dea167SDimitry Andric } 103a7dea167SDimitry Andric 104*0fca6ea1SDimitry Andric Pointer Program::getPtrGlobal(unsigned Idx) const { 105a7dea167SDimitry Andric assert(Idx < Globals.size()); 106a7dea167SDimitry Andric return Pointer(Globals[Idx]->block()); 107a7dea167SDimitry Andric } 108a7dea167SDimitry Andric 109bdd1243dSDimitry Andric std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) { 110*0fca6ea1SDimitry Andric if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end()) 111a7dea167SDimitry Andric return It->second; 112a7dea167SDimitry Andric 113349cc55cSDimitry Andric // Find any previous declarations which were already evaluated. 114bdd1243dSDimitry Andric std::optional<unsigned> Index; 115*0fca6ea1SDimitry Andric for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) { 116*0fca6ea1SDimitry Andric if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) { 117a7dea167SDimitry Andric Index = It->second; 118a7dea167SDimitry Andric break; 119a7dea167SDimitry Andric } 120a7dea167SDimitry Andric } 121a7dea167SDimitry Andric 122a7dea167SDimitry Andric // Map the decl to the existing index. 123*0fca6ea1SDimitry Andric if (Index) 124a7dea167SDimitry Andric GlobalIndices[VD] = *Index; 125*0fca6ea1SDimitry Andric 12606c3fb27SDimitry Andric return std::nullopt; 127a7dea167SDimitry Andric } 128a7dea167SDimitry Andric 129*0fca6ea1SDimitry Andric std::optional<unsigned> Program::getGlobal(const Expr *E) { 130*0fca6ea1SDimitry Andric if (auto It = GlobalIndices.find(E); It != GlobalIndices.end()) 131*0fca6ea1SDimitry Andric return It->second; 132*0fca6ea1SDimitry Andric return std::nullopt; 133a7dea167SDimitry Andric } 134a7dea167SDimitry Andric 135bdd1243dSDimitry Andric std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD, 136bdd1243dSDimitry Andric const Expr *Init) { 137a7dea167SDimitry Andric if (auto Idx = getGlobal(VD)) 138a7dea167SDimitry Andric return Idx; 139a7dea167SDimitry Andric 140bdd1243dSDimitry Andric if (auto Idx = createGlobal(VD, Init)) { 141a7dea167SDimitry Andric GlobalIndices[VD] = *Idx; 142a7dea167SDimitry Andric return Idx; 143a7dea167SDimitry Andric } 14406c3fb27SDimitry Andric return std::nullopt; 145a7dea167SDimitry Andric } 146a7dea167SDimitry Andric 1475f757f3fSDimitry Andric std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) { 14806c3fb27SDimitry Andric // Dedup blocks since they are immutable and pointers cannot be compared. 149*0fca6ea1SDimitry Andric if (auto It = DummyVariables.find(VD); It != DummyVariables.end()) 15006c3fb27SDimitry Andric return It->second; 15106c3fb27SDimitry Andric 152*0fca6ea1SDimitry Andric QualType QT = VD->getType(); 153*0fca6ea1SDimitry Andric if (const auto *RT = QT->getAs<ReferenceType>()) 154*0fca6ea1SDimitry Andric QT = RT->getPointeeType(); 155*0fca6ea1SDimitry Andric 156*0fca6ea1SDimitry Andric Descriptor *Desc; 157*0fca6ea1SDimitry Andric if (std::optional<PrimType> T = Ctx.classify(QT)) 158*0fca6ea1SDimitry Andric Desc = createDescriptor(VD, *T, std::nullopt, true, false); 159*0fca6ea1SDimitry Andric else 160*0fca6ea1SDimitry Andric Desc = createDescriptor(VD, QT.getTypePtr(), std::nullopt, true, false); 161*0fca6ea1SDimitry Andric if (!Desc) 162*0fca6ea1SDimitry Andric Desc = allocateDescriptor(VD); 163*0fca6ea1SDimitry Andric 164*0fca6ea1SDimitry Andric assert(Desc); 165*0fca6ea1SDimitry Andric Desc->makeDummy(); 166*0fca6ea1SDimitry Andric 167*0fca6ea1SDimitry Andric assert(Desc->isDummy()); 168*0fca6ea1SDimitry Andric 1695f757f3fSDimitry Andric // Allocate a block for storage. 1705f757f3fSDimitry Andric unsigned I = Globals.size(); 171a7dea167SDimitry Andric 1725f757f3fSDimitry Andric auto *G = new (Allocator, Desc->getAllocSize()) 173*0fca6ea1SDimitry Andric Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true, 174*0fca6ea1SDimitry Andric /*IsExtern=*/false); 1755f757f3fSDimitry Andric G->block()->invokeCtor(); 1765f757f3fSDimitry Andric 1775f757f3fSDimitry Andric Globals.push_back(G); 178*0fca6ea1SDimitry Andric DummyVariables[VD] = I; 1795f757f3fSDimitry Andric return I; 180a7dea167SDimitry Andric } 181a7dea167SDimitry Andric 182bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, 183bdd1243dSDimitry Andric const Expr *Init) { 184a7dea167SDimitry Andric bool IsStatic, IsExtern; 1855f757f3fSDimitry Andric if (const auto *Var = dyn_cast<VarDecl>(VD)) { 18606c3fb27SDimitry Andric IsStatic = Context::shouldBeGloballyIndexed(VD); 187*0fca6ea1SDimitry Andric IsExtern = Var->hasExternalStorage(); 188*0fca6ea1SDimitry Andric } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl, 189*0fca6ea1SDimitry Andric TemplateParamObjectDecl>(VD)) { 1905f757f3fSDimitry Andric IsStatic = true; 1915f757f3fSDimitry Andric IsExtern = false; 192a7dea167SDimitry Andric } else { 193a7dea167SDimitry Andric IsStatic = false; 194a7dea167SDimitry Andric IsExtern = true; 195a7dea167SDimitry Andric } 196bdd1243dSDimitry Andric if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) { 197a7dea167SDimitry Andric for (const Decl *P = VD; P; P = P->getPreviousDecl()) 198a7dea167SDimitry Andric GlobalIndices[P] = *Idx; 199a7dea167SDimitry Andric return *Idx; 200a7dea167SDimitry Andric } 20106c3fb27SDimitry Andric return std::nullopt; 202a7dea167SDimitry Andric } 203a7dea167SDimitry Andric 204bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const Expr *E) { 205*0fca6ea1SDimitry Andric if (auto Idx = getGlobal(E)) 206*0fca6ea1SDimitry Andric return Idx; 207*0fca6ea1SDimitry Andric if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true, 208*0fca6ea1SDimitry Andric /*isExtern=*/false)) { 209*0fca6ea1SDimitry Andric GlobalIndices[E] = *Idx; 210*0fca6ea1SDimitry Andric return *Idx; 211*0fca6ea1SDimitry Andric } 212*0fca6ea1SDimitry Andric return std::nullopt; 213a7dea167SDimitry Andric } 214a7dea167SDimitry Andric 215bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, 216bdd1243dSDimitry Andric bool IsStatic, bool IsExtern, 217bdd1243dSDimitry Andric const Expr *Init) { 218a7dea167SDimitry Andric // Create a descriptor for the global. 219a7dea167SDimitry Andric Descriptor *Desc; 220a7dea167SDimitry Andric const bool IsConst = Ty.isConstQualified(); 221a7dea167SDimitry Andric const bool IsTemporary = D.dyn_cast<const Expr *>(); 222*0fca6ea1SDimitry Andric if (std::optional<PrimType> T = Ctx.classify(Ty)) 223*0fca6ea1SDimitry Andric Desc = createDescriptor(D, *T, Descriptor::GlobalMD, IsConst, IsTemporary); 224*0fca6ea1SDimitry Andric else 225*0fca6ea1SDimitry Andric Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst, 226bdd1243dSDimitry Andric IsTemporary); 227*0fca6ea1SDimitry Andric 228a7dea167SDimitry Andric if (!Desc) 22906c3fb27SDimitry Andric return std::nullopt; 230a7dea167SDimitry Andric 231a7dea167SDimitry Andric // Allocate a block for storage. 232a7dea167SDimitry Andric unsigned I = Globals.size(); 233a7dea167SDimitry Andric 234a7dea167SDimitry Andric auto *G = new (Allocator, Desc->getAllocSize()) 235*0fca6ea1SDimitry Andric Global(Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern); 236a7dea167SDimitry Andric G->block()->invokeCtor(); 237a7dea167SDimitry Andric 238*0fca6ea1SDimitry Andric // Initialize InlineDescriptor fields. 239*0fca6ea1SDimitry Andric auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor(); 240*0fca6ea1SDimitry Andric if (!Init) 241*0fca6ea1SDimitry Andric GD->InitState = GlobalInitState::NoInitializer; 242a7dea167SDimitry Andric Globals.push_back(G); 243a7dea167SDimitry Andric 244a7dea167SDimitry Andric return I; 245a7dea167SDimitry Andric } 246a7dea167SDimitry Andric 247a7dea167SDimitry Andric Function *Program::getFunction(const FunctionDecl *F) { 248bdd1243dSDimitry Andric F = F->getCanonicalDecl(); 249bdd1243dSDimitry Andric assert(F); 250a7dea167SDimitry Andric auto It = Funcs.find(F); 251a7dea167SDimitry Andric return It == Funcs.end() ? nullptr : It->second.get(); 252a7dea167SDimitry Andric } 253a7dea167SDimitry Andric 254a7dea167SDimitry Andric Record *Program::getOrCreateRecord(const RecordDecl *RD) { 255a7dea167SDimitry Andric // Use the actual definition as a key. 256a7dea167SDimitry Andric RD = RD->getDefinition(); 257a7dea167SDimitry Andric if (!RD) 258a7dea167SDimitry Andric return nullptr; 259a7dea167SDimitry Andric 260*0fca6ea1SDimitry Andric if (!RD->isCompleteDefinition()) 261*0fca6ea1SDimitry Andric return nullptr; 262*0fca6ea1SDimitry Andric 263a7dea167SDimitry Andric // Deduplicate records. 26406c3fb27SDimitry Andric if (auto It = Records.find(RD); It != Records.end()) 265a7dea167SDimitry Andric return It->second; 266a7dea167SDimitry Andric 267bdd1243dSDimitry Andric // We insert nullptr now and replace that later, so recursive calls 268bdd1243dSDimitry Andric // to this function with the same RecordDecl don't run into 269bdd1243dSDimitry Andric // infinite recursion. 270bdd1243dSDimitry Andric Records.insert({RD, nullptr}); 271bdd1243dSDimitry Andric 272a7dea167SDimitry Andric // Number of bytes required by fields and base classes. 273bdd1243dSDimitry Andric unsigned BaseSize = 0; 274a7dea167SDimitry Andric // Number of bytes required by virtual base. 275a7dea167SDimitry Andric unsigned VirtSize = 0; 276a7dea167SDimitry Andric 277a7dea167SDimitry Andric // Helper to get a base descriptor. 278*0fca6ea1SDimitry Andric auto GetBaseDesc = [this](const RecordDecl *BD, 279*0fca6ea1SDimitry Andric const Record *BR) -> const Descriptor * { 280a7dea167SDimitry Andric if (!BR) 281a7dea167SDimitry Andric return nullptr; 282bdd1243dSDimitry Andric return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false, 283a7dea167SDimitry Andric /*isTemporary=*/false, 284a7dea167SDimitry Andric /*isMutable=*/false); 285a7dea167SDimitry Andric }; 286a7dea167SDimitry Andric 287a7dea167SDimitry Andric // Reserve space for base classes. 288a7dea167SDimitry Andric Record::BaseList Bases; 289a7dea167SDimitry Andric Record::VirtualBaseList VirtBases; 290*0fca6ea1SDimitry Andric if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) { 291a7dea167SDimitry Andric for (const CXXBaseSpecifier &Spec : CD->bases()) { 292a7dea167SDimitry Andric if (Spec.isVirtual()) 293a7dea167SDimitry Andric continue; 294a7dea167SDimitry Andric 295*0fca6ea1SDimitry Andric // In error cases, the base might not be a RecordType. 296*0fca6ea1SDimitry Andric const auto *RT = Spec.getType()->getAs<RecordType>(); 297*0fca6ea1SDimitry Andric if (!RT) 298*0fca6ea1SDimitry Andric return nullptr; 299*0fca6ea1SDimitry Andric const RecordDecl *BD = RT->getDecl(); 300*0fca6ea1SDimitry Andric const Record *BR = getOrCreateRecord(BD); 301*0fca6ea1SDimitry Andric 302*0fca6ea1SDimitry Andric const Descriptor *Desc = GetBaseDesc(BD, BR); 303*0fca6ea1SDimitry Andric if (!Desc) 304*0fca6ea1SDimitry Andric return nullptr; 305*0fca6ea1SDimitry Andric 306bdd1243dSDimitry Andric BaseSize += align(sizeof(InlineDescriptor)); 307bdd1243dSDimitry Andric Bases.push_back({BD, BaseSize, Desc, BR}); 308bdd1243dSDimitry Andric BaseSize += align(BR->getSize()); 309a7dea167SDimitry Andric } 310a7dea167SDimitry Andric 311a7dea167SDimitry Andric for (const CXXBaseSpecifier &Spec : CD->vbases()) { 312*0fca6ea1SDimitry Andric const auto *RT = Spec.getType()->getAs<RecordType>(); 313*0fca6ea1SDimitry Andric if (!RT) 314*0fca6ea1SDimitry Andric return nullptr; 315a7dea167SDimitry Andric 316*0fca6ea1SDimitry Andric const RecordDecl *BD = RT->getDecl(); 317*0fca6ea1SDimitry Andric const Record *BR = getOrCreateRecord(BD); 318*0fca6ea1SDimitry Andric 319*0fca6ea1SDimitry Andric const Descriptor *Desc = GetBaseDesc(BD, BR); 320*0fca6ea1SDimitry Andric if (!Desc) 321*0fca6ea1SDimitry Andric return nullptr; 322*0fca6ea1SDimitry Andric 323a7dea167SDimitry Andric VirtSize += align(sizeof(InlineDescriptor)); 324a7dea167SDimitry Andric VirtBases.push_back({BD, VirtSize, Desc, BR}); 325a7dea167SDimitry Andric VirtSize += align(BR->getSize()); 326a7dea167SDimitry Andric } 327a7dea167SDimitry Andric } 328a7dea167SDimitry Andric 329a7dea167SDimitry Andric // Reserve space for fields. 330a7dea167SDimitry Andric Record::FieldList Fields; 331a7dea167SDimitry Andric for (const FieldDecl *FD : RD->fields()) { 332*0fca6ea1SDimitry Andric // Note that we DO create fields and descriptors 333*0fca6ea1SDimitry Andric // for unnamed bitfields here, even though we later ignore 334*0fca6ea1SDimitry Andric // them everywhere. That's so the FieldDecl's getFieldIndex() matches. 335*0fca6ea1SDimitry Andric 336a7dea167SDimitry Andric // Reserve space for the field's descriptor and the offset. 337bdd1243dSDimitry Andric BaseSize += align(sizeof(InlineDescriptor)); 338a7dea167SDimitry Andric 339a7dea167SDimitry Andric // Classify the field and add its metadata. 340a7dea167SDimitry Andric QualType FT = FD->getType(); 341a7dea167SDimitry Andric const bool IsConst = FT.isConstQualified(); 342a7dea167SDimitry Andric const bool IsMutable = FD->isMutable(); 343*0fca6ea1SDimitry Andric const Descriptor *Desc; 344bdd1243dSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(FT)) { 345bdd1243dSDimitry Andric Desc = createDescriptor(FD, *T, std::nullopt, IsConst, 346bdd1243dSDimitry Andric /*isTemporary=*/false, IsMutable); 347a7dea167SDimitry Andric } else { 348bdd1243dSDimitry Andric Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst, 349a7dea167SDimitry Andric /*isTemporary=*/false, IsMutable); 350a7dea167SDimitry Andric } 351a7dea167SDimitry Andric if (!Desc) 352a7dea167SDimitry Andric return nullptr; 353bdd1243dSDimitry Andric Fields.push_back({FD, BaseSize, Desc}); 354bdd1243dSDimitry Andric BaseSize += align(Desc->getAllocSize()); 355a7dea167SDimitry Andric } 356a7dea167SDimitry Andric 357a7dea167SDimitry Andric Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields), 358bdd1243dSDimitry Andric std::move(VirtBases), VirtSize, BaseSize); 359bdd1243dSDimitry Andric Records[RD] = R; 360a7dea167SDimitry Andric return R; 361a7dea167SDimitry Andric } 362a7dea167SDimitry Andric 363a7dea167SDimitry Andric Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, 364bdd1243dSDimitry Andric Descriptor::MetadataSize MDSize, 365a7dea167SDimitry Andric bool IsConst, bool IsTemporary, 366bdd1243dSDimitry Andric bool IsMutable, const Expr *Init) { 367*0fca6ea1SDimitry Andric 368a7dea167SDimitry Andric // Classes and structures. 369297eecfbSDimitry Andric if (const auto *RT = Ty->getAs<RecordType>()) { 370297eecfbSDimitry Andric if (const auto *Record = getOrCreateRecord(RT->getDecl())) 371bdd1243dSDimitry Andric return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, 372bdd1243dSDimitry Andric IsMutable); 373a7dea167SDimitry Andric } 374a7dea167SDimitry Andric 375a7dea167SDimitry Andric // Arrays. 376297eecfbSDimitry Andric if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) { 377a7dea167SDimitry Andric QualType ElemTy = ArrayType->getElementType(); 378a7dea167SDimitry Andric // Array of well-known bounds. 379a7dea167SDimitry Andric if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) { 380*0fca6ea1SDimitry Andric size_t NumElems = CAT->getZExtSize(); 381bdd1243dSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 382a7dea167SDimitry Andric // Arrays of primitives. 383a7dea167SDimitry Andric unsigned ElemSize = primSize(*T); 384a7dea167SDimitry Andric if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { 385a7dea167SDimitry Andric return {}; 386a7dea167SDimitry Andric } 387bdd1243dSDimitry Andric return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary, 388a7dea167SDimitry Andric IsMutable); 389a7dea167SDimitry Andric } else { 390a7dea167SDimitry Andric // Arrays of composites. In this case, the array is a list of pointers, 391a7dea167SDimitry Andric // followed by the actual elements. 392297eecfbSDimitry Andric const Descriptor *ElemDesc = createDescriptor( 393bdd1243dSDimitry Andric D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); 394bdd1243dSDimitry Andric if (!ElemDesc) 395a7dea167SDimitry Andric return nullptr; 39606c3fb27SDimitry Andric unsigned ElemSize = 397bdd1243dSDimitry Andric ElemDesc->getAllocSize() + sizeof(InlineDescriptor); 398a7dea167SDimitry Andric if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) 399a7dea167SDimitry Andric return {}; 400bdd1243dSDimitry Andric return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst, 401bdd1243dSDimitry Andric IsTemporary, IsMutable); 402a7dea167SDimitry Andric } 403a7dea167SDimitry Andric } 404a7dea167SDimitry Andric 405a7dea167SDimitry Andric // Array of unknown bounds - cannot be accessed and pointer arithmetic 406a7dea167SDimitry Andric // is forbidden on pointers to such objects. 407*0fca6ea1SDimitry Andric if (isa<IncompleteArrayType>(ArrayType) || 408*0fca6ea1SDimitry Andric isa<VariableArrayType>(ArrayType)) { 409bdd1243dSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 410*0fca6ea1SDimitry Andric return allocateDescriptor(D, *T, MDSize, IsTemporary, 411a7dea167SDimitry Andric Descriptor::UnknownSize{}); 412a7dea167SDimitry Andric } else { 413297eecfbSDimitry Andric const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), 414297eecfbSDimitry Andric MDSize, IsConst, IsTemporary); 415a7dea167SDimitry Andric if (!Desc) 416a7dea167SDimitry Andric return nullptr; 417*0fca6ea1SDimitry Andric return allocateDescriptor(D, Desc, MDSize, IsTemporary, 418a7dea167SDimitry Andric Descriptor::UnknownSize{}); 419a7dea167SDimitry Andric } 420a7dea167SDimitry Andric } 421a7dea167SDimitry Andric } 422a7dea167SDimitry Andric 423a7dea167SDimitry Andric // Atomic types. 424297eecfbSDimitry Andric if (const auto *AT = Ty->getAs<AtomicType>()) { 425a7dea167SDimitry Andric const Type *InnerTy = AT->getValueType().getTypePtr(); 426bdd1243dSDimitry Andric return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary, 427bdd1243dSDimitry Andric IsMutable); 428a7dea167SDimitry Andric } 429a7dea167SDimitry Andric 430a7dea167SDimitry Andric // Complex types - represented as arrays of elements. 431297eecfbSDimitry Andric if (const auto *CT = Ty->getAs<ComplexType>()) { 432a7dea167SDimitry Andric PrimType ElemTy = *Ctx.classify(CT->getElementType()); 433bdd1243dSDimitry Andric return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary, 434bdd1243dSDimitry Andric IsMutable); 435a7dea167SDimitry Andric } 436a7dea167SDimitry Andric 437*0fca6ea1SDimitry Andric // Same with vector types. 438*0fca6ea1SDimitry Andric if (const auto *VT = Ty->getAs<VectorType>()) { 439*0fca6ea1SDimitry Andric PrimType ElemTy = *Ctx.classify(VT->getElementType()); 440*0fca6ea1SDimitry Andric return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst, 441*0fca6ea1SDimitry Andric IsTemporary, IsMutable); 442*0fca6ea1SDimitry Andric } 443*0fca6ea1SDimitry Andric 444a7dea167SDimitry Andric return nullptr; 445a7dea167SDimitry Andric } 446