xref: /src/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1519fc96cSDimitry Andric //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===//
2519fc96cSDimitry Andric //
3519fc96cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4519fc96cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5519fc96cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6519fc96cSDimitry Andric //
7519fc96cSDimitry Andric //===----------------------------------------------------------------------===//
8519fc96cSDimitry Andric 
9519fc96cSDimitry Andric #include "Program.h"
10519fc96cSDimitry Andric #include "Context.h"
11519fc96cSDimitry Andric #include "Function.h"
127fa27ce4SDimitry Andric #include "Integral.h"
13519fc96cSDimitry Andric #include "Opcode.h"
14519fc96cSDimitry Andric #include "PrimType.h"
15519fc96cSDimitry Andric #include "clang/AST/Decl.h"
16519fc96cSDimitry Andric #include "clang/AST/DeclCXX.h"
17519fc96cSDimitry Andric 
18519fc96cSDimitry Andric using namespace clang;
19519fc96cSDimitry Andric using namespace clang::interp;
20519fc96cSDimitry Andric 
getOrCreateNativePointer(const void * Ptr)21c0981da4SDimitry Andric unsigned Program::getOrCreateNativePointer(const void *Ptr) {
22c0981da4SDimitry Andric   auto It = NativePointerIndices.find(Ptr);
23c0981da4SDimitry Andric   if (It != NativePointerIndices.end())
24c0981da4SDimitry Andric     return It->second;
25c0981da4SDimitry Andric 
26c0981da4SDimitry Andric   unsigned Idx = NativePointers.size();
27c0981da4SDimitry Andric   NativePointers.push_back(Ptr);
28c0981da4SDimitry Andric   NativePointerIndices[Ptr] = Idx;
29c0981da4SDimitry Andric   return Idx;
30c0981da4SDimitry Andric }
31c0981da4SDimitry Andric 
getNativePointer(unsigned Idx)32c0981da4SDimitry Andric const void *Program::getNativePointer(unsigned Idx) {
33c0981da4SDimitry Andric   return NativePointers[Idx];
34c0981da4SDimitry Andric }
35c0981da4SDimitry Andric 
createGlobalString(const StringLiteral * S)36519fc96cSDimitry Andric unsigned Program::createGlobalString(const StringLiteral *S) {
37519fc96cSDimitry Andric   const size_t CharWidth = S->getCharByteWidth();
38519fc96cSDimitry Andric   const size_t BitWidth = CharWidth * Ctx.getCharBit();
39519fc96cSDimitry Andric 
40519fc96cSDimitry Andric   PrimType CharType;
41519fc96cSDimitry Andric   switch (CharWidth) {
42519fc96cSDimitry Andric   case 1:
43519fc96cSDimitry Andric     CharType = PT_Sint8;
44519fc96cSDimitry Andric     break;
45519fc96cSDimitry Andric   case 2:
46519fc96cSDimitry Andric     CharType = PT_Uint16;
47519fc96cSDimitry Andric     break;
48519fc96cSDimitry Andric   case 4:
49519fc96cSDimitry Andric     CharType = PT_Uint32;
50519fc96cSDimitry Andric     break;
51519fc96cSDimitry Andric   default:
52519fc96cSDimitry Andric     llvm_unreachable("unsupported character width");
53519fc96cSDimitry Andric   }
54519fc96cSDimitry Andric 
55519fc96cSDimitry Andric   // Create a descriptor for the string.
56e3b55780SDimitry Andric   Descriptor *Desc =
57ac9a064cSDimitry Andric       allocateDescriptor(S, CharType, Descriptor::GlobalMD, S->getLength() + 1,
58519fc96cSDimitry Andric                          /*isConst=*/true,
59519fc96cSDimitry Andric                          /*isTemporary=*/false,
60519fc96cSDimitry Andric                          /*isMutable=*/false);
61519fc96cSDimitry Andric 
62519fc96cSDimitry Andric   // Allocate storage for the string.
63519fc96cSDimitry Andric   // The byte length does not include the null terminator.
64519fc96cSDimitry Andric   unsigned I = Globals.size();
65519fc96cSDimitry Andric   unsigned Sz = Desc->getAllocSize();
66ac9a064cSDimitry Andric   auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true,
67519fc96cSDimitry Andric                                        /*isExtern=*/false);
68e3b55780SDimitry Andric   G->block()->invokeCtor();
69ac9a064cSDimitry Andric 
70ac9a064cSDimitry Andric   new (G->block()->rawData()) InlineDescriptor(Desc);
71519fc96cSDimitry Andric   Globals.push_back(G);
72519fc96cSDimitry Andric 
73519fc96cSDimitry Andric   // Construct the string in storage.
74519fc96cSDimitry Andric   const Pointer Ptr(G->block());
75519fc96cSDimitry Andric   for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {
76519fc96cSDimitry Andric     Pointer Field = Ptr.atIndex(I).narrow();
77519fc96cSDimitry Andric     const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);
78519fc96cSDimitry Andric     switch (CharType) {
79519fc96cSDimitry Andric       case PT_Sint8: {
80519fc96cSDimitry Andric         using T = PrimConv<PT_Sint8>::T;
81519fc96cSDimitry Andric         Field.deref<T>() = T::from(CodePoint, BitWidth);
82ac9a064cSDimitry Andric         Field.initialize();
83519fc96cSDimitry Andric         break;
84519fc96cSDimitry Andric       }
85519fc96cSDimitry Andric       case PT_Uint16: {
86519fc96cSDimitry Andric         using T = PrimConv<PT_Uint16>::T;
87519fc96cSDimitry Andric         Field.deref<T>() = T::from(CodePoint, BitWidth);
88ac9a064cSDimitry Andric         Field.initialize();
89519fc96cSDimitry Andric         break;
90519fc96cSDimitry Andric       }
91519fc96cSDimitry Andric       case PT_Uint32: {
92519fc96cSDimitry Andric         using T = PrimConv<PT_Uint32>::T;
93519fc96cSDimitry Andric         Field.deref<T>() = T::from(CodePoint, BitWidth);
94ac9a064cSDimitry Andric         Field.initialize();
95519fc96cSDimitry Andric         break;
96519fc96cSDimitry Andric       }
97519fc96cSDimitry Andric       default:
98519fc96cSDimitry Andric         llvm_unreachable("unsupported character type");
99519fc96cSDimitry Andric     }
100519fc96cSDimitry Andric   }
101519fc96cSDimitry Andric   return I;
102519fc96cSDimitry Andric }
103519fc96cSDimitry Andric 
getPtrGlobal(unsigned Idx) const104ac9a064cSDimitry Andric Pointer Program::getPtrGlobal(unsigned Idx) const {
105519fc96cSDimitry Andric   assert(Idx < Globals.size());
106519fc96cSDimitry Andric   return Pointer(Globals[Idx]->block());
107519fc96cSDimitry Andric }
108519fc96cSDimitry Andric 
getGlobal(const ValueDecl * VD)109e3b55780SDimitry Andric std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
110ac9a064cSDimitry Andric   if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
111519fc96cSDimitry Andric     return It->second;
112519fc96cSDimitry Andric 
113c0981da4SDimitry Andric   // Find any previous declarations which were already evaluated.
114e3b55780SDimitry Andric   std::optional<unsigned> Index;
115ac9a064cSDimitry Andric   for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) {
116ac9a064cSDimitry Andric     if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) {
117519fc96cSDimitry Andric       Index = It->second;
118519fc96cSDimitry Andric       break;
119519fc96cSDimitry Andric     }
120519fc96cSDimitry Andric   }
121519fc96cSDimitry Andric 
122519fc96cSDimitry Andric   // Map the decl to the existing index.
123ac9a064cSDimitry Andric   if (Index)
124519fc96cSDimitry Andric     GlobalIndices[VD] = *Index;
125ac9a064cSDimitry Andric 
1267fa27ce4SDimitry Andric   return std::nullopt;
127519fc96cSDimitry Andric }
128519fc96cSDimitry Andric 
getGlobal(const Expr * E)129ac9a064cSDimitry Andric std::optional<unsigned> Program::getGlobal(const Expr *E) {
130ac9a064cSDimitry Andric   if (auto It = GlobalIndices.find(E); It != GlobalIndices.end())
131ac9a064cSDimitry Andric     return It->second;
132ac9a064cSDimitry Andric   return std::nullopt;
133519fc96cSDimitry Andric }
134519fc96cSDimitry Andric 
getOrCreateGlobal(const ValueDecl * VD,const Expr * Init)135e3b55780SDimitry Andric std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
136e3b55780SDimitry Andric                                                    const Expr *Init) {
137519fc96cSDimitry Andric   if (auto Idx = getGlobal(VD))
138519fc96cSDimitry Andric     return Idx;
139519fc96cSDimitry Andric 
140e3b55780SDimitry Andric   if (auto Idx = createGlobal(VD, Init)) {
141519fc96cSDimitry Andric     GlobalIndices[VD] = *Idx;
142519fc96cSDimitry Andric     return Idx;
143519fc96cSDimitry Andric   }
1447fa27ce4SDimitry Andric   return std::nullopt;
145519fc96cSDimitry Andric }
146519fc96cSDimitry Andric 
getOrCreateDummy(const ValueDecl * VD)147b1c73532SDimitry Andric std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
1487fa27ce4SDimitry Andric   // Dedup blocks since they are immutable and pointers cannot be compared.
149ac9a064cSDimitry Andric   if (auto It = DummyVariables.find(VD); It != DummyVariables.end())
1507fa27ce4SDimitry Andric     return It->second;
1517fa27ce4SDimitry Andric 
152ac9a064cSDimitry Andric   QualType QT = VD->getType();
153ac9a064cSDimitry Andric   if (const auto *RT = QT->getAs<ReferenceType>())
154ac9a064cSDimitry Andric     QT = RT->getPointeeType();
155ac9a064cSDimitry Andric 
156ac9a064cSDimitry Andric   Descriptor *Desc;
157ac9a064cSDimitry Andric   if (std::optional<PrimType> T = Ctx.classify(QT))
158ac9a064cSDimitry Andric     Desc = createDescriptor(VD, *T, std::nullopt, true, false);
159ac9a064cSDimitry Andric   else
160ac9a064cSDimitry Andric     Desc = createDescriptor(VD, QT.getTypePtr(), std::nullopt, true, false);
161ac9a064cSDimitry Andric   if (!Desc)
162ac9a064cSDimitry Andric     Desc = allocateDescriptor(VD);
163ac9a064cSDimitry Andric 
164ac9a064cSDimitry Andric   assert(Desc);
165ac9a064cSDimitry Andric   Desc->makeDummy();
166ac9a064cSDimitry Andric 
167ac9a064cSDimitry Andric   assert(Desc->isDummy());
168ac9a064cSDimitry Andric 
169b1c73532SDimitry Andric   // Allocate a block for storage.
170b1c73532SDimitry Andric   unsigned I = Globals.size();
171519fc96cSDimitry Andric 
172b1c73532SDimitry Andric   auto *G = new (Allocator, Desc->getAllocSize())
173ac9a064cSDimitry Andric       Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true,
174ac9a064cSDimitry Andric              /*IsExtern=*/false);
175b1c73532SDimitry Andric   G->block()->invokeCtor();
176b1c73532SDimitry Andric 
177b1c73532SDimitry Andric   Globals.push_back(G);
178ac9a064cSDimitry Andric   DummyVariables[VD] = I;
179b1c73532SDimitry Andric   return I;
180519fc96cSDimitry Andric }
181519fc96cSDimitry Andric 
createGlobal(const ValueDecl * VD,const Expr * Init)182e3b55780SDimitry Andric std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
183e3b55780SDimitry Andric                                               const Expr *Init) {
184519fc96cSDimitry Andric   bool IsStatic, IsExtern;
185b1c73532SDimitry Andric   if (const auto *Var = dyn_cast<VarDecl>(VD)) {
1867fa27ce4SDimitry Andric     IsStatic = Context::shouldBeGloballyIndexed(VD);
187ac9a064cSDimitry Andric     IsExtern = Var->hasExternalStorage();
188ac9a064cSDimitry Andric   } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl,
189ac9a064cSDimitry Andric                  TemplateParamObjectDecl>(VD)) {
190b1c73532SDimitry Andric     IsStatic = true;
191b1c73532SDimitry Andric     IsExtern = false;
192519fc96cSDimitry Andric   } else {
193519fc96cSDimitry Andric     IsStatic = false;
194519fc96cSDimitry Andric     IsExtern = true;
195519fc96cSDimitry Andric   }
196e3b55780SDimitry Andric   if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) {
197519fc96cSDimitry Andric     for (const Decl *P = VD; P; P = P->getPreviousDecl())
198519fc96cSDimitry Andric       GlobalIndices[P] = *Idx;
199519fc96cSDimitry Andric     return *Idx;
200519fc96cSDimitry Andric   }
2017fa27ce4SDimitry Andric   return std::nullopt;
202519fc96cSDimitry Andric }
203519fc96cSDimitry Andric 
createGlobal(const Expr * E)204e3b55780SDimitry Andric std::optional<unsigned> Program::createGlobal(const Expr *E) {
205ac9a064cSDimitry Andric   if (auto Idx = getGlobal(E))
206ac9a064cSDimitry Andric     return Idx;
207ac9a064cSDimitry Andric   if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true,
208ac9a064cSDimitry Andric                               /*isExtern=*/false)) {
209ac9a064cSDimitry Andric     GlobalIndices[E] = *Idx;
210ac9a064cSDimitry Andric     return *Idx;
211ac9a064cSDimitry Andric   }
212ac9a064cSDimitry Andric   return std::nullopt;
213519fc96cSDimitry Andric }
214519fc96cSDimitry Andric 
createGlobal(const DeclTy & D,QualType Ty,bool IsStatic,bool IsExtern,const Expr * Init)215e3b55780SDimitry Andric std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
216e3b55780SDimitry Andric                                               bool IsStatic, bool IsExtern,
217e3b55780SDimitry Andric                                               const Expr *Init) {
218519fc96cSDimitry Andric   // Create a descriptor for the global.
219519fc96cSDimitry Andric   Descriptor *Desc;
220519fc96cSDimitry Andric   const bool IsConst = Ty.isConstQualified();
221519fc96cSDimitry Andric   const bool IsTemporary = D.dyn_cast<const Expr *>();
222ac9a064cSDimitry Andric   if (std::optional<PrimType> T = Ctx.classify(Ty))
223ac9a064cSDimitry Andric     Desc = createDescriptor(D, *T, Descriptor::GlobalMD, IsConst, IsTemporary);
224ac9a064cSDimitry Andric   else
225ac9a064cSDimitry Andric     Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst,
226e3b55780SDimitry Andric                             IsTemporary);
227ac9a064cSDimitry Andric 
228519fc96cSDimitry Andric   if (!Desc)
2297fa27ce4SDimitry Andric     return std::nullopt;
230519fc96cSDimitry Andric 
231519fc96cSDimitry Andric   // Allocate a block for storage.
232519fc96cSDimitry Andric   unsigned I = Globals.size();
233519fc96cSDimitry Andric 
234519fc96cSDimitry Andric   auto *G = new (Allocator, Desc->getAllocSize())
235ac9a064cSDimitry Andric       Global(Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern);
236519fc96cSDimitry Andric   G->block()->invokeCtor();
237519fc96cSDimitry Andric 
238ac9a064cSDimitry Andric   // Initialize InlineDescriptor fields.
239ac9a064cSDimitry Andric   auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor();
240ac9a064cSDimitry Andric   if (!Init)
241ac9a064cSDimitry Andric     GD->InitState = GlobalInitState::NoInitializer;
242519fc96cSDimitry Andric   Globals.push_back(G);
243519fc96cSDimitry Andric 
244519fc96cSDimitry Andric   return I;
245519fc96cSDimitry Andric }
246519fc96cSDimitry Andric 
getFunction(const FunctionDecl * F)247519fc96cSDimitry Andric Function *Program::getFunction(const FunctionDecl *F) {
248e3b55780SDimitry Andric   F = F->getCanonicalDecl();
249e3b55780SDimitry Andric   assert(F);
250519fc96cSDimitry Andric   auto It = Funcs.find(F);
251519fc96cSDimitry Andric   return It == Funcs.end() ? nullptr : It->second.get();
252519fc96cSDimitry Andric }
253519fc96cSDimitry Andric 
getOrCreateRecord(const RecordDecl * RD)254519fc96cSDimitry Andric Record *Program::getOrCreateRecord(const RecordDecl *RD) {
255519fc96cSDimitry Andric   // Use the actual definition as a key.
256519fc96cSDimitry Andric   RD = RD->getDefinition();
257519fc96cSDimitry Andric   if (!RD)
258519fc96cSDimitry Andric     return nullptr;
259519fc96cSDimitry Andric 
260ac9a064cSDimitry Andric   if (!RD->isCompleteDefinition())
261ac9a064cSDimitry Andric     return nullptr;
262ac9a064cSDimitry Andric 
263519fc96cSDimitry Andric   // Deduplicate records.
2647fa27ce4SDimitry Andric   if (auto It = Records.find(RD); It != Records.end())
265519fc96cSDimitry Andric     return It->second;
266519fc96cSDimitry Andric 
267e3b55780SDimitry Andric   // We insert nullptr now and replace that later, so recursive calls
268e3b55780SDimitry Andric   // to this function with the same RecordDecl don't run into
269e3b55780SDimitry Andric   // infinite recursion.
270e3b55780SDimitry Andric   Records.insert({RD, nullptr});
271e3b55780SDimitry Andric 
272519fc96cSDimitry Andric   // Number of bytes required by fields and base classes.
273e3b55780SDimitry Andric   unsigned BaseSize = 0;
274519fc96cSDimitry Andric   // Number of bytes required by virtual base.
275519fc96cSDimitry Andric   unsigned VirtSize = 0;
276519fc96cSDimitry Andric 
277519fc96cSDimitry Andric   // Helper to get a base descriptor.
278ac9a064cSDimitry Andric   auto GetBaseDesc = [this](const RecordDecl *BD,
279ac9a064cSDimitry Andric                             const Record *BR) -> const Descriptor * {
280519fc96cSDimitry Andric     if (!BR)
281519fc96cSDimitry Andric       return nullptr;
282e3b55780SDimitry Andric     return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,
283519fc96cSDimitry Andric                               /*isTemporary=*/false,
284519fc96cSDimitry Andric                               /*isMutable=*/false);
285519fc96cSDimitry Andric   };
286519fc96cSDimitry Andric 
287519fc96cSDimitry Andric   // Reserve space for base classes.
288519fc96cSDimitry Andric   Record::BaseList Bases;
289519fc96cSDimitry Andric   Record::VirtualBaseList VirtBases;
290ac9a064cSDimitry Andric   if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
291519fc96cSDimitry Andric     for (const CXXBaseSpecifier &Spec : CD->bases()) {
292519fc96cSDimitry Andric       if (Spec.isVirtual())
293519fc96cSDimitry Andric         continue;
294519fc96cSDimitry Andric 
295ac9a064cSDimitry Andric       // In error cases, the base might not be a RecordType.
296ac9a064cSDimitry Andric       const auto *RT = Spec.getType()->getAs<RecordType>();
297ac9a064cSDimitry Andric       if (!RT)
298ac9a064cSDimitry Andric         return nullptr;
299ac9a064cSDimitry Andric       const RecordDecl *BD = RT->getDecl();
300ac9a064cSDimitry Andric       const Record *BR = getOrCreateRecord(BD);
301ac9a064cSDimitry Andric 
302ac9a064cSDimitry Andric       const Descriptor *Desc = GetBaseDesc(BD, BR);
303ac9a064cSDimitry Andric       if (!Desc)
304ac9a064cSDimitry Andric         return nullptr;
305ac9a064cSDimitry Andric 
306e3b55780SDimitry Andric       BaseSize += align(sizeof(InlineDescriptor));
307e3b55780SDimitry Andric       Bases.push_back({BD, BaseSize, Desc, BR});
308e3b55780SDimitry Andric       BaseSize += align(BR->getSize());
309519fc96cSDimitry Andric     }
310519fc96cSDimitry Andric 
311519fc96cSDimitry Andric     for (const CXXBaseSpecifier &Spec : CD->vbases()) {
312ac9a064cSDimitry Andric       const auto *RT = Spec.getType()->getAs<RecordType>();
313ac9a064cSDimitry Andric       if (!RT)
314ac9a064cSDimitry Andric         return nullptr;
315519fc96cSDimitry Andric 
316ac9a064cSDimitry Andric       const RecordDecl *BD = RT->getDecl();
317ac9a064cSDimitry Andric       const Record *BR = getOrCreateRecord(BD);
318ac9a064cSDimitry Andric 
319ac9a064cSDimitry Andric       const Descriptor *Desc = GetBaseDesc(BD, BR);
320ac9a064cSDimitry Andric       if (!Desc)
321ac9a064cSDimitry Andric         return nullptr;
322ac9a064cSDimitry Andric 
323519fc96cSDimitry Andric       VirtSize += align(sizeof(InlineDescriptor));
324519fc96cSDimitry Andric       VirtBases.push_back({BD, VirtSize, Desc, BR});
325519fc96cSDimitry Andric       VirtSize += align(BR->getSize());
326519fc96cSDimitry Andric     }
327519fc96cSDimitry Andric   }
328519fc96cSDimitry Andric 
329519fc96cSDimitry Andric   // Reserve space for fields.
330519fc96cSDimitry Andric   Record::FieldList Fields;
331519fc96cSDimitry Andric   for (const FieldDecl *FD : RD->fields()) {
332ac9a064cSDimitry Andric     // Note that we DO create fields and descriptors
333ac9a064cSDimitry Andric     // for unnamed bitfields here, even though we later ignore
334ac9a064cSDimitry Andric     // them everywhere. That's so the FieldDecl's getFieldIndex() matches.
335ac9a064cSDimitry Andric 
336519fc96cSDimitry Andric     // Reserve space for the field's descriptor and the offset.
337e3b55780SDimitry Andric     BaseSize += align(sizeof(InlineDescriptor));
338519fc96cSDimitry Andric 
339519fc96cSDimitry Andric     // Classify the field and add its metadata.
340519fc96cSDimitry Andric     QualType FT = FD->getType();
341519fc96cSDimitry Andric     const bool IsConst = FT.isConstQualified();
342519fc96cSDimitry Andric     const bool IsMutable = FD->isMutable();
343ac9a064cSDimitry Andric     const Descriptor *Desc;
344e3b55780SDimitry Andric     if (std::optional<PrimType> T = Ctx.classify(FT)) {
345e3b55780SDimitry Andric       Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
346e3b55780SDimitry Andric                               /*isTemporary=*/false, IsMutable);
347519fc96cSDimitry Andric     } else {
348e3b55780SDimitry Andric       Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,
349519fc96cSDimitry Andric                               /*isTemporary=*/false, IsMutable);
350519fc96cSDimitry Andric     }
351519fc96cSDimitry Andric     if (!Desc)
352519fc96cSDimitry Andric       return nullptr;
353e3b55780SDimitry Andric     Fields.push_back({FD, BaseSize, Desc});
354e3b55780SDimitry Andric     BaseSize += align(Desc->getAllocSize());
355519fc96cSDimitry Andric   }
356519fc96cSDimitry Andric 
357519fc96cSDimitry Andric   Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
358e3b55780SDimitry Andric                                      std::move(VirtBases), VirtSize, BaseSize);
359e3b55780SDimitry Andric   Records[RD] = R;
360519fc96cSDimitry Andric   return R;
361519fc96cSDimitry Andric }
362519fc96cSDimitry Andric 
createDescriptor(const DeclTy & D,const Type * Ty,Descriptor::MetadataSize MDSize,bool IsConst,bool IsTemporary,bool IsMutable,const Expr * Init)363519fc96cSDimitry Andric Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
364e3b55780SDimitry Andric                                       Descriptor::MetadataSize MDSize,
365519fc96cSDimitry Andric                                       bool IsConst, bool IsTemporary,
366e3b55780SDimitry Andric                                       bool IsMutable, const Expr *Init) {
367ac9a064cSDimitry Andric 
368519fc96cSDimitry Andric   // Classes and structures.
369950076cdSDimitry Andric   if (const auto *RT = Ty->getAs<RecordType>()) {
370950076cdSDimitry Andric     if (const auto *Record = getOrCreateRecord(RT->getDecl()))
371e3b55780SDimitry Andric       return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
372e3b55780SDimitry Andric                                 IsMutable);
373519fc96cSDimitry Andric   }
374519fc96cSDimitry Andric 
375519fc96cSDimitry Andric   // Arrays.
376950076cdSDimitry Andric   if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
377519fc96cSDimitry Andric     QualType ElemTy = ArrayType->getElementType();
378519fc96cSDimitry Andric     // Array of well-known bounds.
379519fc96cSDimitry Andric     if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
380ac9a064cSDimitry Andric       size_t NumElems = CAT->getZExtSize();
381e3b55780SDimitry Andric       if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
382519fc96cSDimitry Andric         // Arrays of primitives.
383519fc96cSDimitry Andric         unsigned ElemSize = primSize(*T);
384519fc96cSDimitry Andric         if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
385519fc96cSDimitry Andric           return {};
386519fc96cSDimitry Andric         }
387e3b55780SDimitry Andric         return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary,
388519fc96cSDimitry Andric                                   IsMutable);
389519fc96cSDimitry Andric       } else {
390519fc96cSDimitry Andric         // Arrays of composites. In this case, the array is a list of pointers,
391519fc96cSDimitry Andric         // followed by the actual elements.
392950076cdSDimitry Andric         const Descriptor *ElemDesc = createDescriptor(
393e3b55780SDimitry Andric             D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
394e3b55780SDimitry Andric         if (!ElemDesc)
395519fc96cSDimitry Andric           return nullptr;
3967fa27ce4SDimitry Andric         unsigned ElemSize =
397e3b55780SDimitry Andric             ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
398519fc96cSDimitry Andric         if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
399519fc96cSDimitry Andric           return {};
400e3b55780SDimitry Andric         return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst,
401e3b55780SDimitry Andric                                   IsTemporary, IsMutable);
402519fc96cSDimitry Andric       }
403519fc96cSDimitry Andric     }
404519fc96cSDimitry Andric 
405519fc96cSDimitry Andric     // Array of unknown bounds - cannot be accessed and pointer arithmetic
406519fc96cSDimitry Andric     // is forbidden on pointers to such objects.
407ac9a064cSDimitry Andric     if (isa<IncompleteArrayType>(ArrayType) ||
408ac9a064cSDimitry Andric         isa<VariableArrayType>(ArrayType)) {
409e3b55780SDimitry Andric       if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
410ac9a064cSDimitry Andric         return allocateDescriptor(D, *T, MDSize, IsTemporary,
411519fc96cSDimitry Andric                                   Descriptor::UnknownSize{});
412519fc96cSDimitry Andric       } else {
413950076cdSDimitry Andric         const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(),
414950076cdSDimitry Andric                                                   MDSize, IsConst, IsTemporary);
415519fc96cSDimitry Andric         if (!Desc)
416519fc96cSDimitry Andric           return nullptr;
417ac9a064cSDimitry Andric         return allocateDescriptor(D, Desc, MDSize, IsTemporary,
418519fc96cSDimitry Andric                                   Descriptor::UnknownSize{});
419519fc96cSDimitry Andric       }
420519fc96cSDimitry Andric     }
421519fc96cSDimitry Andric   }
422519fc96cSDimitry Andric 
423519fc96cSDimitry Andric   // Atomic types.
424950076cdSDimitry Andric   if (const auto *AT = Ty->getAs<AtomicType>()) {
425519fc96cSDimitry Andric     const Type *InnerTy = AT->getValueType().getTypePtr();
426e3b55780SDimitry Andric     return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,
427e3b55780SDimitry Andric                             IsMutable);
428519fc96cSDimitry Andric   }
429519fc96cSDimitry Andric 
430519fc96cSDimitry Andric   // Complex types - represented as arrays of elements.
431950076cdSDimitry Andric   if (const auto *CT = Ty->getAs<ComplexType>()) {
432519fc96cSDimitry Andric     PrimType ElemTy = *Ctx.classify(CT->getElementType());
433e3b55780SDimitry Andric     return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,
434e3b55780SDimitry Andric                               IsMutable);
435519fc96cSDimitry Andric   }
436519fc96cSDimitry Andric 
437ac9a064cSDimitry Andric   // Same with vector types.
438ac9a064cSDimitry Andric   if (const auto *VT = Ty->getAs<VectorType>()) {
439ac9a064cSDimitry Andric     PrimType ElemTy = *Ctx.classify(VT->getElementType());
440ac9a064cSDimitry Andric     return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst,
441ac9a064cSDimitry Andric                               IsTemporary, IsMutable);
442ac9a064cSDimitry Andric   }
443ac9a064cSDimitry Andric 
444519fc96cSDimitry Andric   return nullptr;
445519fc96cSDimitry Andric }
446