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