xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
getOrCreateNativePointer(const void * Ptr)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 
getNativePointer(unsigned Idx)32349cc55cSDimitry Andric const void *Program::getNativePointer(unsigned Idx) {
33349cc55cSDimitry Andric   return NativePointers[Idx];
34349cc55cSDimitry Andric }
35349cc55cSDimitry Andric 
createGlobalString(const StringLiteral * S)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 
getPtrGlobal(unsigned Idx) const104*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 
getGlobal(const ValueDecl * VD)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 
getGlobal(const Expr * E)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 
getOrCreateGlobal(const ValueDecl * VD,const Expr * Init)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 
getOrCreateDummy(const ValueDecl * VD)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 
createGlobal(const ValueDecl * VD,const Expr * Init)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 
createGlobal(const Expr * E)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 
createGlobal(const DeclTy & D,QualType Ty,bool IsStatic,bool IsExtern,const Expr * Init)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 
getFunction(const FunctionDecl * F)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 
getOrCreateRecord(const RecordDecl * RD)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 
createDescriptor(const DeclTy & D,const Type * Ty,Descriptor::MetadataSize MDSize,bool IsConst,bool IsTemporary,bool IsMutable,const Expr * Init)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