1a07aba5dSTimm Baeder //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===// 2a07aba5dSTimm Baeder // 3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a07aba5dSTimm Baeder // 7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 8a07aba5dSTimm Baeder 9a07aba5dSTimm Baeder #include "Program.h" 10a07aba5dSTimm Baeder #include "Context.h" 11a07aba5dSTimm Baeder #include "Function.h" 12a07aba5dSTimm Baeder #include "Integral.h" 13a07aba5dSTimm Baeder #include "PrimType.h" 14a07aba5dSTimm Baeder #include "clang/AST/Decl.h" 15a07aba5dSTimm Baeder #include "clang/AST/DeclCXX.h" 16a07aba5dSTimm Baeder 17a07aba5dSTimm Baeder using namespace clang; 18a07aba5dSTimm Baeder using namespace clang::interp; 19a07aba5dSTimm Baeder 20a07aba5dSTimm Baeder unsigned Program::getOrCreateNativePointer(const void *Ptr) { 21a07aba5dSTimm Baeder auto It = NativePointerIndices.find(Ptr); 22a07aba5dSTimm Baeder if (It != NativePointerIndices.end()) 23a07aba5dSTimm Baeder return It->second; 24a07aba5dSTimm Baeder 25a07aba5dSTimm Baeder unsigned Idx = NativePointers.size(); 26a07aba5dSTimm Baeder NativePointers.push_back(Ptr); 27a07aba5dSTimm Baeder NativePointerIndices[Ptr] = Idx; 28a07aba5dSTimm Baeder return Idx; 29a07aba5dSTimm Baeder } 30a07aba5dSTimm Baeder 31a07aba5dSTimm Baeder const void *Program::getNativePointer(unsigned Idx) { 32a07aba5dSTimm Baeder return NativePointers[Idx]; 33a07aba5dSTimm Baeder } 34a07aba5dSTimm Baeder 35ff04bb8fSTimm Baeder unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) { 36a07aba5dSTimm Baeder const size_t CharWidth = S->getCharByteWidth(); 37a07aba5dSTimm Baeder const size_t BitWidth = CharWidth * Ctx.getCharBit(); 38a07aba5dSTimm Baeder 39a07aba5dSTimm Baeder PrimType CharType; 40a07aba5dSTimm Baeder switch (CharWidth) { 41a07aba5dSTimm Baeder case 1: 42a07aba5dSTimm Baeder CharType = PT_Sint8; 43a07aba5dSTimm Baeder break; 44a07aba5dSTimm Baeder case 2: 45a07aba5dSTimm Baeder CharType = PT_Uint16; 46a07aba5dSTimm Baeder break; 47a07aba5dSTimm Baeder case 4: 48a07aba5dSTimm Baeder CharType = PT_Uint32; 49a07aba5dSTimm Baeder break; 50a07aba5dSTimm Baeder default: 51a07aba5dSTimm Baeder llvm_unreachable("unsupported character width"); 52a07aba5dSTimm Baeder } 53a07aba5dSTimm Baeder 54ff04bb8fSTimm Baeder if (!Base) 55ff04bb8fSTimm Baeder Base = S; 56ff04bb8fSTimm Baeder 57a07aba5dSTimm Baeder // Create a descriptor for the string. 58ff04bb8fSTimm Baeder Descriptor *Desc = allocateDescriptor(Base, CharType, Descriptor::GlobalMD, 59ff04bb8fSTimm Baeder S->getLength() + 1, 60a07aba5dSTimm Baeder /*isConst=*/true, 61a07aba5dSTimm Baeder /*isTemporary=*/false, 62a07aba5dSTimm Baeder /*isMutable=*/false); 63a07aba5dSTimm Baeder 64a07aba5dSTimm Baeder // Allocate storage for the string. 65a07aba5dSTimm Baeder // The byte length does not include the null terminator. 66a07aba5dSTimm Baeder unsigned I = Globals.size(); 67a07aba5dSTimm Baeder unsigned Sz = Desc->getAllocSize(); 68a07aba5dSTimm Baeder auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true, 69a07aba5dSTimm Baeder /*isExtern=*/false); 70a07aba5dSTimm Baeder G->block()->invokeCtor(); 71a07aba5dSTimm Baeder 72a07aba5dSTimm Baeder new (G->block()->rawData()) InlineDescriptor(Desc); 73a07aba5dSTimm Baeder Globals.push_back(G); 74a07aba5dSTimm Baeder 75a07aba5dSTimm Baeder // Construct the string in storage. 76a07aba5dSTimm Baeder const Pointer Ptr(G->block()); 77a07aba5dSTimm Baeder for (unsigned I = 0, N = S->getLength(); I <= N; ++I) { 78a07aba5dSTimm Baeder Pointer Field = Ptr.atIndex(I).narrow(); 79a07aba5dSTimm Baeder const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I); 80a07aba5dSTimm Baeder switch (CharType) { 81a07aba5dSTimm Baeder case PT_Sint8: { 82a07aba5dSTimm Baeder using T = PrimConv<PT_Sint8>::T; 83a07aba5dSTimm Baeder Field.deref<T>() = T::from(CodePoint, BitWidth); 84a07aba5dSTimm Baeder Field.initialize(); 85a07aba5dSTimm Baeder break; 86a07aba5dSTimm Baeder } 87a07aba5dSTimm Baeder case PT_Uint16: { 88a07aba5dSTimm Baeder using T = PrimConv<PT_Uint16>::T; 89a07aba5dSTimm Baeder Field.deref<T>() = T::from(CodePoint, BitWidth); 90a07aba5dSTimm Baeder Field.initialize(); 91a07aba5dSTimm Baeder break; 92a07aba5dSTimm Baeder } 93a07aba5dSTimm Baeder case PT_Uint32: { 94a07aba5dSTimm Baeder using T = PrimConv<PT_Uint32>::T; 95a07aba5dSTimm Baeder Field.deref<T>() = T::from(CodePoint, BitWidth); 96a07aba5dSTimm Baeder Field.initialize(); 97a07aba5dSTimm Baeder break; 98a07aba5dSTimm Baeder } 99a07aba5dSTimm Baeder default: 100a07aba5dSTimm Baeder llvm_unreachable("unsupported character type"); 101a07aba5dSTimm Baeder } 102a07aba5dSTimm Baeder } 103a07aba5dSTimm Baeder return I; 104a07aba5dSTimm Baeder } 105a07aba5dSTimm Baeder 106a07aba5dSTimm Baeder Pointer Program::getPtrGlobal(unsigned Idx) const { 107a07aba5dSTimm Baeder assert(Idx < Globals.size()); 108a07aba5dSTimm Baeder return Pointer(Globals[Idx]->block()); 109a07aba5dSTimm Baeder } 110a07aba5dSTimm Baeder 111a07aba5dSTimm Baeder std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) { 112a07aba5dSTimm Baeder if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end()) 113a07aba5dSTimm Baeder return It->second; 114a07aba5dSTimm Baeder 115a07aba5dSTimm Baeder // Find any previous declarations which were already evaluated. 116a07aba5dSTimm Baeder std::optional<unsigned> Index; 117a07aba5dSTimm Baeder for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) { 118a07aba5dSTimm Baeder if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) { 119a07aba5dSTimm Baeder Index = It->second; 120a07aba5dSTimm Baeder break; 121a07aba5dSTimm Baeder } 122a07aba5dSTimm Baeder } 123a07aba5dSTimm Baeder 124a07aba5dSTimm Baeder // Map the decl to the existing index. 125a07aba5dSTimm Baeder if (Index) 126a07aba5dSTimm Baeder GlobalIndices[VD] = *Index; 127a07aba5dSTimm Baeder 128a07aba5dSTimm Baeder return std::nullopt; 129a07aba5dSTimm Baeder } 130a07aba5dSTimm Baeder 131a07aba5dSTimm Baeder std::optional<unsigned> Program::getGlobal(const Expr *E) { 132a07aba5dSTimm Baeder if (auto It = GlobalIndices.find(E); It != GlobalIndices.end()) 133a07aba5dSTimm Baeder return It->second; 134a07aba5dSTimm Baeder return std::nullopt; 135a07aba5dSTimm Baeder } 136a07aba5dSTimm Baeder 137a07aba5dSTimm Baeder std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD, 138a07aba5dSTimm Baeder const Expr *Init) { 139a07aba5dSTimm Baeder if (auto Idx = getGlobal(VD)) 140a07aba5dSTimm Baeder return Idx; 141a07aba5dSTimm Baeder 142a07aba5dSTimm Baeder if (auto Idx = createGlobal(VD, Init)) { 143a07aba5dSTimm Baeder GlobalIndices[VD] = *Idx; 144a07aba5dSTimm Baeder return Idx; 145a07aba5dSTimm Baeder } 146a07aba5dSTimm Baeder return std::nullopt; 147a07aba5dSTimm Baeder } 148a07aba5dSTimm Baeder 1499ae41c24STimm Baeder unsigned Program::getOrCreateDummy(const DeclTy &D) { 150bd8d432dSTimm Baeder assert(D); 151a07aba5dSTimm Baeder // Dedup blocks since they are immutable and pointers cannot be compared. 152bd8d432dSTimm Baeder if (auto It = DummyVariables.find(D.getOpaqueValue()); 153bd8d432dSTimm Baeder It != DummyVariables.end()) 154a07aba5dSTimm Baeder return It->second; 155a07aba5dSTimm Baeder 156bd8d432dSTimm Baeder QualType QT; 1574e5f8a8fSTimm Baeder bool IsWeak = false; 15880e0cbafSKazu Hirata if (const auto *E = dyn_cast<const Expr *>(D)) { 159bd8d432dSTimm Baeder QT = E->getType(); 160bd8d432dSTimm Baeder } else { 16163d9ef5eSKazu Hirata const ValueDecl *VD = cast<ValueDecl>(cast<const Decl *>(D)); 1624e5f8a8fSTimm Baeder IsWeak = VD->isWeak(); 163bd8d432dSTimm Baeder QT = VD->getType(); 164a07aba5dSTimm Baeder if (const auto *RT = QT->getAs<ReferenceType>()) 165a07aba5dSTimm Baeder QT = RT->getPointeeType(); 166bd8d432dSTimm Baeder } 167bd8d432dSTimm Baeder assert(!QT.isNull()); 168a07aba5dSTimm Baeder 169a07aba5dSTimm Baeder Descriptor *Desc; 170a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(QT)) 171bd8d432dSTimm Baeder Desc = createDescriptor(D, *T, std::nullopt, /*IsTemporary=*/true, 172bd8d432dSTimm Baeder /*IsMutable=*/false); 173a07aba5dSTimm Baeder else 174bd8d432dSTimm Baeder Desc = createDescriptor(D, QT.getTypePtr(), std::nullopt, 175bd8d432dSTimm Baeder /*IsTemporary=*/true, /*IsMutable=*/false); 176a07aba5dSTimm Baeder if (!Desc) 177bd8d432dSTimm Baeder Desc = allocateDescriptor(D); 178a07aba5dSTimm Baeder 179a07aba5dSTimm Baeder assert(Desc); 180a07aba5dSTimm Baeder Desc->makeDummy(); 181a07aba5dSTimm Baeder 182a07aba5dSTimm Baeder assert(Desc->isDummy()); 183a07aba5dSTimm Baeder 184a07aba5dSTimm Baeder // Allocate a block for storage. 185a07aba5dSTimm Baeder unsigned I = Globals.size(); 186a07aba5dSTimm Baeder 187a07aba5dSTimm Baeder auto *G = new (Allocator, Desc->getAllocSize()) 188a07aba5dSTimm Baeder Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true, 1894e5f8a8fSTimm Baeder /*IsExtern=*/false, IsWeak); 190a07aba5dSTimm Baeder G->block()->invokeCtor(); 191a07aba5dSTimm Baeder 192a07aba5dSTimm Baeder Globals.push_back(G); 193bd8d432dSTimm Baeder DummyVariables[D.getOpaqueValue()] = I; 194a07aba5dSTimm Baeder return I; 195a07aba5dSTimm Baeder } 196a07aba5dSTimm Baeder 197a07aba5dSTimm Baeder std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, 198a07aba5dSTimm Baeder const Expr *Init) { 199a07aba5dSTimm Baeder bool IsStatic, IsExtern; 2004e5f8a8fSTimm Baeder bool IsWeak = VD->isWeak(); 201a07aba5dSTimm Baeder if (const auto *Var = dyn_cast<VarDecl>(VD)) { 202a07aba5dSTimm Baeder IsStatic = Context::shouldBeGloballyIndexed(VD); 203a07aba5dSTimm Baeder IsExtern = Var->hasExternalStorage(); 204a07aba5dSTimm Baeder } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl, 205a07aba5dSTimm Baeder TemplateParamObjectDecl>(VD)) { 206a07aba5dSTimm Baeder IsStatic = true; 207a07aba5dSTimm Baeder IsExtern = false; 208a07aba5dSTimm Baeder } else { 209a07aba5dSTimm Baeder IsStatic = false; 210a07aba5dSTimm Baeder IsExtern = true; 211a07aba5dSTimm Baeder } 2128e2dbab2STimm Baeder 2138e2dbab2STimm Baeder // Register all previous declarations as well. For extern blocks, just replace 2148e2dbab2STimm Baeder // the index with the new variable. 2154e5f8a8fSTimm Baeder if (auto Idx = 2164e5f8a8fSTimm Baeder createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init)) { 2178e2dbab2STimm Baeder for (const Decl *P = VD; P; P = P->getPreviousDecl()) { 2188e2dbab2STimm Baeder if (P != VD) { 2198e2dbab2STimm Baeder unsigned PIdx = GlobalIndices[P]; 2208e2dbab2STimm Baeder if (Globals[PIdx]->block()->isExtern()) 2218e2dbab2STimm Baeder Globals[PIdx] = Globals[*Idx]; 2228e2dbab2STimm Baeder } 223a07aba5dSTimm Baeder GlobalIndices[P] = *Idx; 2248e2dbab2STimm Baeder } 225a07aba5dSTimm Baeder return *Idx; 226a07aba5dSTimm Baeder } 227a07aba5dSTimm Baeder return std::nullopt; 228a07aba5dSTimm Baeder } 229a07aba5dSTimm Baeder 230a07aba5dSTimm Baeder std::optional<unsigned> Program::createGlobal(const Expr *E) { 231a07aba5dSTimm Baeder if (auto Idx = getGlobal(E)) 232a07aba5dSTimm Baeder return Idx; 233a07aba5dSTimm Baeder if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true, 2344e5f8a8fSTimm Baeder /*isExtern=*/false, /*IsWeak=*/false)) { 235a07aba5dSTimm Baeder GlobalIndices[E] = *Idx; 236a07aba5dSTimm Baeder return *Idx; 237a07aba5dSTimm Baeder } 238a07aba5dSTimm Baeder return std::nullopt; 239a07aba5dSTimm Baeder } 240a07aba5dSTimm Baeder 241a07aba5dSTimm Baeder std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, 242a07aba5dSTimm Baeder bool IsStatic, bool IsExtern, 2434e5f8a8fSTimm Baeder bool IsWeak, const Expr *Init) { 244a07aba5dSTimm Baeder // Create a descriptor for the global. 245a07aba5dSTimm Baeder Descriptor *Desc; 246a07aba5dSTimm Baeder const bool IsConst = Ty.isConstQualified(); 247a07aba5dSTimm Baeder const bool IsTemporary = D.dyn_cast<const Expr *>(); 248a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(Ty)) 249a07aba5dSTimm Baeder Desc = createDescriptor(D, *T, Descriptor::GlobalMD, IsConst, IsTemporary); 250a07aba5dSTimm Baeder else 251a07aba5dSTimm Baeder Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst, 252a07aba5dSTimm Baeder IsTemporary); 253a07aba5dSTimm Baeder 254a07aba5dSTimm Baeder if (!Desc) 255a07aba5dSTimm Baeder return std::nullopt; 256a07aba5dSTimm Baeder 257a07aba5dSTimm Baeder // Allocate a block for storage. 258a07aba5dSTimm Baeder unsigned I = Globals.size(); 259a07aba5dSTimm Baeder 2604e5f8a8fSTimm Baeder auto *G = new (Allocator, Desc->getAllocSize()) Global( 2614e5f8a8fSTimm Baeder Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern, IsWeak); 262a07aba5dSTimm Baeder G->block()->invokeCtor(); 263a07aba5dSTimm Baeder 264a07aba5dSTimm Baeder // Initialize InlineDescriptor fields. 265a07aba5dSTimm Baeder auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor(); 266a07aba5dSTimm Baeder if (!Init) 267a07aba5dSTimm Baeder GD->InitState = GlobalInitState::NoInitializer; 268a07aba5dSTimm Baeder Globals.push_back(G); 269a07aba5dSTimm Baeder 270a07aba5dSTimm Baeder return I; 271a07aba5dSTimm Baeder } 272a07aba5dSTimm Baeder 273a07aba5dSTimm Baeder Function *Program::getFunction(const FunctionDecl *F) { 274a07aba5dSTimm Baeder F = F->getCanonicalDecl(); 275a07aba5dSTimm Baeder assert(F); 276a07aba5dSTimm Baeder auto It = Funcs.find(F); 277a07aba5dSTimm Baeder return It == Funcs.end() ? nullptr : It->second.get(); 278a07aba5dSTimm Baeder } 279a07aba5dSTimm Baeder 280a07aba5dSTimm Baeder Record *Program::getOrCreateRecord(const RecordDecl *RD) { 281a07aba5dSTimm Baeder // Use the actual definition as a key. 282a07aba5dSTimm Baeder RD = RD->getDefinition(); 283a07aba5dSTimm Baeder if (!RD) 284a07aba5dSTimm Baeder return nullptr; 285a07aba5dSTimm Baeder 286a07aba5dSTimm Baeder if (!RD->isCompleteDefinition()) 287a07aba5dSTimm Baeder return nullptr; 288a07aba5dSTimm Baeder 28993f7fce3SKazu Hirata // Return an existing record if available. Otherwise, we insert nullptr now 29093f7fce3SKazu Hirata // and replace that later, so recursive calls to this function with the same 29193f7fce3SKazu Hirata // RecordDecl don't run into infinite recursion. 29293f7fce3SKazu Hirata auto [It, Inserted] = Records.try_emplace(RD); 29393f7fce3SKazu Hirata if (!Inserted) 294a07aba5dSTimm Baeder return It->second; 295a07aba5dSTimm Baeder 296a07aba5dSTimm Baeder // Number of bytes required by fields and base classes. 297a07aba5dSTimm Baeder unsigned BaseSize = 0; 298a07aba5dSTimm Baeder // Number of bytes required by virtual base. 299a07aba5dSTimm Baeder unsigned VirtSize = 0; 300a07aba5dSTimm Baeder 301a07aba5dSTimm Baeder // Helper to get a base descriptor. 302a07aba5dSTimm Baeder auto GetBaseDesc = [this](const RecordDecl *BD, 303a07aba5dSTimm Baeder const Record *BR) -> const Descriptor * { 304a07aba5dSTimm Baeder if (!BR) 305a07aba5dSTimm Baeder return nullptr; 306a07aba5dSTimm Baeder return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false, 307a07aba5dSTimm Baeder /*isTemporary=*/false, 308a07aba5dSTimm Baeder /*isMutable=*/false); 309a07aba5dSTimm Baeder }; 310a07aba5dSTimm Baeder 311a07aba5dSTimm Baeder // Reserve space for base classes. 312a07aba5dSTimm Baeder Record::BaseList Bases; 313a07aba5dSTimm Baeder Record::VirtualBaseList VirtBases; 314a07aba5dSTimm Baeder if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) { 315a07aba5dSTimm Baeder for (const CXXBaseSpecifier &Spec : CD->bases()) { 316a07aba5dSTimm Baeder if (Spec.isVirtual()) 317a07aba5dSTimm Baeder continue; 318a07aba5dSTimm Baeder 319a07aba5dSTimm Baeder // In error cases, the base might not be a RecordType. 320a07aba5dSTimm Baeder const auto *RT = Spec.getType()->getAs<RecordType>(); 321a07aba5dSTimm Baeder if (!RT) 322a07aba5dSTimm Baeder return nullptr; 323a07aba5dSTimm Baeder const RecordDecl *BD = RT->getDecl(); 324a07aba5dSTimm Baeder const Record *BR = getOrCreateRecord(BD); 325a07aba5dSTimm Baeder 326a07aba5dSTimm Baeder const Descriptor *Desc = GetBaseDesc(BD, BR); 327a07aba5dSTimm Baeder if (!Desc) 328a07aba5dSTimm Baeder return nullptr; 329a07aba5dSTimm Baeder 330a07aba5dSTimm Baeder BaseSize += align(sizeof(InlineDescriptor)); 331a07aba5dSTimm Baeder Bases.push_back({BD, BaseSize, Desc, BR}); 332a07aba5dSTimm Baeder BaseSize += align(BR->getSize()); 333a07aba5dSTimm Baeder } 334a07aba5dSTimm Baeder 335a07aba5dSTimm Baeder for (const CXXBaseSpecifier &Spec : CD->vbases()) { 336a07aba5dSTimm Baeder const auto *RT = Spec.getType()->getAs<RecordType>(); 337a07aba5dSTimm Baeder if (!RT) 338a07aba5dSTimm Baeder return nullptr; 339a07aba5dSTimm Baeder 340a07aba5dSTimm Baeder const RecordDecl *BD = RT->getDecl(); 341a07aba5dSTimm Baeder const Record *BR = getOrCreateRecord(BD); 342a07aba5dSTimm Baeder 343a07aba5dSTimm Baeder const Descriptor *Desc = GetBaseDesc(BD, BR); 344a07aba5dSTimm Baeder if (!Desc) 345a07aba5dSTimm Baeder return nullptr; 346a07aba5dSTimm Baeder 347a07aba5dSTimm Baeder VirtSize += align(sizeof(InlineDescriptor)); 348a07aba5dSTimm Baeder VirtBases.push_back({BD, VirtSize, Desc, BR}); 349a07aba5dSTimm Baeder VirtSize += align(BR->getSize()); 350a07aba5dSTimm Baeder } 351a07aba5dSTimm Baeder } 352a07aba5dSTimm Baeder 353a07aba5dSTimm Baeder // Reserve space for fields. 354a07aba5dSTimm Baeder Record::FieldList Fields; 355a07aba5dSTimm Baeder for (const FieldDecl *FD : RD->fields()) { 3563e999bbcSTimm Baeder FD = FD->getFirstDecl(); 357a07aba5dSTimm Baeder // Note that we DO create fields and descriptors 358a07aba5dSTimm Baeder // for unnamed bitfields here, even though we later ignore 359a07aba5dSTimm Baeder // them everywhere. That's so the FieldDecl's getFieldIndex() matches. 360a07aba5dSTimm Baeder 361a07aba5dSTimm Baeder // Reserve space for the field's descriptor and the offset. 362a07aba5dSTimm Baeder BaseSize += align(sizeof(InlineDescriptor)); 363a07aba5dSTimm Baeder 364a07aba5dSTimm Baeder // Classify the field and add its metadata. 365a07aba5dSTimm Baeder QualType FT = FD->getType(); 366a07aba5dSTimm Baeder const bool IsConst = FT.isConstQualified(); 367a07aba5dSTimm Baeder const bool IsMutable = FD->isMutable(); 368a07aba5dSTimm Baeder const Descriptor *Desc; 369a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(FT)) { 370a07aba5dSTimm Baeder Desc = createDescriptor(FD, *T, std::nullopt, IsConst, 371a07aba5dSTimm Baeder /*isTemporary=*/false, IsMutable); 372a07aba5dSTimm Baeder } else { 373a07aba5dSTimm Baeder Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst, 374a07aba5dSTimm Baeder /*isTemporary=*/false, IsMutable); 375a07aba5dSTimm Baeder } 376a07aba5dSTimm Baeder if (!Desc) 377a07aba5dSTimm Baeder return nullptr; 378a07aba5dSTimm Baeder Fields.push_back({FD, BaseSize, Desc}); 379a07aba5dSTimm Baeder BaseSize += align(Desc->getAllocSize()); 380a07aba5dSTimm Baeder } 381a07aba5dSTimm Baeder 382a07aba5dSTimm Baeder Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields), 383a07aba5dSTimm Baeder std::move(VirtBases), VirtSize, BaseSize); 384a07aba5dSTimm Baeder Records[RD] = R; 385a07aba5dSTimm Baeder return R; 386a07aba5dSTimm Baeder } 387a07aba5dSTimm Baeder 388a07aba5dSTimm Baeder Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, 389a07aba5dSTimm Baeder Descriptor::MetadataSize MDSize, 390a07aba5dSTimm Baeder bool IsConst, bool IsTemporary, 391a07aba5dSTimm Baeder bool IsMutable, const Expr *Init) { 392a07aba5dSTimm Baeder 393a07aba5dSTimm Baeder // Classes and structures. 394a07aba5dSTimm Baeder if (const auto *RT = Ty->getAs<RecordType>()) { 395a07aba5dSTimm Baeder if (const auto *Record = getOrCreateRecord(RT->getDecl())) 396a07aba5dSTimm Baeder return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, 397a07aba5dSTimm Baeder IsMutable); 398a07aba5dSTimm Baeder } 399a07aba5dSTimm Baeder 400a07aba5dSTimm Baeder // Arrays. 40105910b44STimm Baeder if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) { 402a07aba5dSTimm Baeder QualType ElemTy = ArrayType->getElementType(); 403a07aba5dSTimm Baeder // Array of well-known bounds. 40405910b44STimm Baeder if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) { 405a07aba5dSTimm Baeder size_t NumElems = CAT->getZExtSize(); 406a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 407a07aba5dSTimm Baeder // Arrays of primitives. 408a07aba5dSTimm Baeder unsigned ElemSize = primSize(*T); 409a07aba5dSTimm Baeder if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { 410a07aba5dSTimm Baeder return {}; 411a07aba5dSTimm Baeder } 412a07aba5dSTimm Baeder return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary, 413a07aba5dSTimm Baeder IsMutable); 414a07aba5dSTimm Baeder } else { 415a07aba5dSTimm Baeder // Arrays of composites. In this case, the array is a list of pointers, 416a07aba5dSTimm Baeder // followed by the actual elements. 417a07aba5dSTimm Baeder const Descriptor *ElemDesc = createDescriptor( 418a07aba5dSTimm Baeder D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); 419a07aba5dSTimm Baeder if (!ElemDesc) 420a07aba5dSTimm Baeder return nullptr; 421a07aba5dSTimm Baeder unsigned ElemSize = ElemDesc->getAllocSize() + sizeof(InlineDescriptor); 422a07aba5dSTimm Baeder if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) 423a07aba5dSTimm Baeder return {}; 424a07aba5dSTimm Baeder return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst, 425a07aba5dSTimm Baeder IsTemporary, IsMutable); 426a07aba5dSTimm Baeder } 427a07aba5dSTimm Baeder } 428a07aba5dSTimm Baeder 429a07aba5dSTimm Baeder // Array of unknown bounds - cannot be accessed and pointer arithmetic 430a07aba5dSTimm Baeder // is forbidden on pointers to such objects. 431a07aba5dSTimm Baeder if (isa<IncompleteArrayType>(ArrayType) || 432a07aba5dSTimm Baeder isa<VariableArrayType>(ArrayType)) { 433a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 434a07aba5dSTimm Baeder return allocateDescriptor(D, *T, MDSize, IsTemporary, 435a07aba5dSTimm Baeder Descriptor::UnknownSize{}); 436a07aba5dSTimm Baeder } else { 437a07aba5dSTimm Baeder const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), 438a07aba5dSTimm Baeder MDSize, IsConst, IsTemporary); 439a07aba5dSTimm Baeder if (!Desc) 440a07aba5dSTimm Baeder return nullptr; 441a07aba5dSTimm Baeder return allocateDescriptor(D, Desc, MDSize, IsTemporary, 442a07aba5dSTimm Baeder Descriptor::UnknownSize{}); 443a07aba5dSTimm Baeder } 444a07aba5dSTimm Baeder } 445a07aba5dSTimm Baeder } 446a07aba5dSTimm Baeder 447a07aba5dSTimm Baeder // Atomic types. 448a07aba5dSTimm Baeder if (const auto *AT = Ty->getAs<AtomicType>()) { 449a07aba5dSTimm Baeder const Type *InnerTy = AT->getValueType().getTypePtr(); 450a07aba5dSTimm Baeder return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary, 451a07aba5dSTimm Baeder IsMutable); 452a07aba5dSTimm Baeder } 453a07aba5dSTimm Baeder 454a07aba5dSTimm Baeder // Complex types - represented as arrays of elements. 455a07aba5dSTimm Baeder if (const auto *CT = Ty->getAs<ComplexType>()) { 456*a34a087fSTimm Baeder std::optional<PrimType> ElemTy = Ctx.classify(CT->getElementType()); 457*a34a087fSTimm Baeder if (!ElemTy) 458*a34a087fSTimm Baeder return nullptr; 459*a34a087fSTimm Baeder 460*a34a087fSTimm Baeder return allocateDescriptor(D, *ElemTy, MDSize, 2, IsConst, IsTemporary, 461a07aba5dSTimm Baeder IsMutable); 462a07aba5dSTimm Baeder } 463a07aba5dSTimm Baeder 464a07aba5dSTimm Baeder // Same with vector types. 465a07aba5dSTimm Baeder if (const auto *VT = Ty->getAs<VectorType>()) { 466*a34a087fSTimm Baeder std::optional<PrimType> ElemTy = Ctx.classify(VT->getElementType()); 467*a34a087fSTimm Baeder if (!ElemTy) 468*a34a087fSTimm Baeder return nullptr; 469*a34a087fSTimm Baeder 470*a34a087fSTimm Baeder return allocateDescriptor(D, *ElemTy, MDSize, VT->getNumElements(), IsConst, 471a07aba5dSTimm Baeder IsTemporary, IsMutable); 472a07aba5dSTimm Baeder } 473a07aba5dSTimm Baeder 474a07aba5dSTimm Baeder return nullptr; 475a07aba5dSTimm Baeder } 476