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