xref: /llvm-project/clang/lib/AST/ByteCode/Program.cpp (revision a34a087fc59779c53512eda094e1ca914a4526f2)
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