1*700637cbSDimitry Andric //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric
9*700637cbSDimitry Andric #include "Program.h"
10*700637cbSDimitry Andric #include "Context.h"
11*700637cbSDimitry Andric #include "Function.h"
12*700637cbSDimitry Andric #include "Integral.h"
13*700637cbSDimitry Andric #include "PrimType.h"
14*700637cbSDimitry Andric #include "clang/AST/Decl.h"
15*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h"
16*700637cbSDimitry Andric
17*700637cbSDimitry Andric using namespace clang;
18*700637cbSDimitry Andric using namespace clang::interp;
19*700637cbSDimitry Andric
getOrCreateNativePointer(const void * Ptr)20*700637cbSDimitry Andric unsigned Program::getOrCreateNativePointer(const void *Ptr) {
21*700637cbSDimitry Andric auto [It, Inserted] =
22*700637cbSDimitry Andric NativePointerIndices.try_emplace(Ptr, NativePointers.size());
23*700637cbSDimitry Andric if (Inserted)
24*700637cbSDimitry Andric NativePointers.push_back(Ptr);
25*700637cbSDimitry Andric
26*700637cbSDimitry Andric return It->second;
27*700637cbSDimitry Andric }
28*700637cbSDimitry Andric
getNativePointer(unsigned Idx)29*700637cbSDimitry Andric const void *Program::getNativePointer(unsigned Idx) {
30*700637cbSDimitry Andric return NativePointers[Idx];
31*700637cbSDimitry Andric }
32*700637cbSDimitry Andric
createGlobalString(const StringLiteral * S,const Expr * Base)33*700637cbSDimitry Andric unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) {
34*700637cbSDimitry Andric const size_t CharWidth = S->getCharByteWidth();
35*700637cbSDimitry Andric const size_t BitWidth = CharWidth * Ctx.getCharBit();
36*700637cbSDimitry Andric unsigned StringLength = S->getLength();
37*700637cbSDimitry Andric
38*700637cbSDimitry Andric PrimType CharType;
39*700637cbSDimitry Andric switch (CharWidth) {
40*700637cbSDimitry Andric case 1:
41*700637cbSDimitry Andric CharType = PT_Sint8;
42*700637cbSDimitry Andric break;
43*700637cbSDimitry Andric case 2:
44*700637cbSDimitry Andric CharType = PT_Uint16;
45*700637cbSDimitry Andric break;
46*700637cbSDimitry Andric case 4:
47*700637cbSDimitry Andric CharType = PT_Uint32;
48*700637cbSDimitry Andric break;
49*700637cbSDimitry Andric default:
50*700637cbSDimitry Andric llvm_unreachable("unsupported character width");
51*700637cbSDimitry Andric }
52*700637cbSDimitry Andric
53*700637cbSDimitry Andric if (!Base)
54*700637cbSDimitry Andric Base = S;
55*700637cbSDimitry Andric
56*700637cbSDimitry Andric // Create a descriptor for the string.
57*700637cbSDimitry Andric Descriptor *Desc =
58*700637cbSDimitry Andric allocateDescriptor(Base, CharType, Descriptor::GlobalMD, StringLength + 1,
59*700637cbSDimitry Andric /*isConst=*/true,
60*700637cbSDimitry Andric /*isTemporary=*/false,
61*700637cbSDimitry Andric /*isMutable=*/false);
62*700637cbSDimitry Andric
63*700637cbSDimitry Andric // Allocate storage for the string.
64*700637cbSDimitry Andric // The byte length does not include the null terminator.
65*700637cbSDimitry Andric unsigned GlobalIndex = Globals.size();
66*700637cbSDimitry Andric unsigned Sz = Desc->getAllocSize();
67*700637cbSDimitry Andric auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true,
68*700637cbSDimitry Andric /*isExtern=*/false);
69*700637cbSDimitry Andric G->block()->invokeCtor();
70*700637cbSDimitry Andric
71*700637cbSDimitry Andric new (G->block()->rawData())
72*700637cbSDimitry Andric GlobalInlineDescriptor{GlobalInitState::Initialized};
73*700637cbSDimitry Andric Globals.push_back(G);
74*700637cbSDimitry Andric
75*700637cbSDimitry Andric const Pointer Ptr(G->block());
76*700637cbSDimitry Andric if (CharWidth == 1) {
77*700637cbSDimitry Andric std::memcpy(&Ptr.atIndex(0).deref<char>(), S->getString().data(),
78*700637cbSDimitry Andric StringLength);
79*700637cbSDimitry Andric } else {
80*700637cbSDimitry Andric // Construct the string in storage.
81*700637cbSDimitry Andric for (unsigned I = 0; I <= StringLength; ++I) {
82*700637cbSDimitry Andric Pointer Field = Ptr.atIndex(I);
83*700637cbSDimitry Andric const uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
84*700637cbSDimitry Andric switch (CharType) {
85*700637cbSDimitry Andric case PT_Sint8: {
86*700637cbSDimitry Andric using T = PrimConv<PT_Sint8>::T;
87*700637cbSDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth);
88*700637cbSDimitry Andric break;
89*700637cbSDimitry Andric }
90*700637cbSDimitry Andric case PT_Uint16: {
91*700637cbSDimitry Andric using T = PrimConv<PT_Uint16>::T;
92*700637cbSDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth);
93*700637cbSDimitry Andric break;
94*700637cbSDimitry Andric }
95*700637cbSDimitry Andric case PT_Uint32: {
96*700637cbSDimitry Andric using T = PrimConv<PT_Uint32>::T;
97*700637cbSDimitry Andric Field.deref<T>() = T::from(CodePoint, BitWidth);
98*700637cbSDimitry Andric break;
99*700637cbSDimitry Andric }
100*700637cbSDimitry Andric default:
101*700637cbSDimitry Andric llvm_unreachable("unsupported character type");
102*700637cbSDimitry Andric }
103*700637cbSDimitry Andric }
104*700637cbSDimitry Andric }
105*700637cbSDimitry Andric Ptr.initialize();
106*700637cbSDimitry Andric
107*700637cbSDimitry Andric return GlobalIndex;
108*700637cbSDimitry Andric }
109*700637cbSDimitry Andric
getPtrGlobal(unsigned Idx) const110*700637cbSDimitry Andric Pointer Program::getPtrGlobal(unsigned Idx) const {
111*700637cbSDimitry Andric assert(Idx < Globals.size());
112*700637cbSDimitry Andric return Pointer(Globals[Idx]->block());
113*700637cbSDimitry Andric }
114*700637cbSDimitry Andric
getGlobal(const ValueDecl * VD)115*700637cbSDimitry Andric std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
116*700637cbSDimitry Andric if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
117*700637cbSDimitry Andric return It->second;
118*700637cbSDimitry Andric
119*700637cbSDimitry Andric // Find any previous declarations which were already evaluated.
120*700637cbSDimitry Andric std::optional<unsigned> Index;
121*700637cbSDimitry Andric for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) {
122*700637cbSDimitry Andric if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) {
123*700637cbSDimitry Andric Index = It->second;
124*700637cbSDimitry Andric break;
125*700637cbSDimitry Andric }
126*700637cbSDimitry Andric }
127*700637cbSDimitry Andric
128*700637cbSDimitry Andric // Map the decl to the existing index.
129*700637cbSDimitry Andric if (Index)
130*700637cbSDimitry Andric GlobalIndices[VD] = *Index;
131*700637cbSDimitry Andric
132*700637cbSDimitry Andric return std::nullopt;
133*700637cbSDimitry Andric }
134*700637cbSDimitry Andric
getGlobal(const Expr * E)135*700637cbSDimitry Andric std::optional<unsigned> Program::getGlobal(const Expr *E) {
136*700637cbSDimitry Andric if (auto It = GlobalIndices.find(E); It != GlobalIndices.end())
137*700637cbSDimitry Andric return It->second;
138*700637cbSDimitry Andric return std::nullopt;
139*700637cbSDimitry Andric }
140*700637cbSDimitry Andric
getOrCreateGlobal(const ValueDecl * VD,const Expr * Init)141*700637cbSDimitry Andric std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
142*700637cbSDimitry Andric const Expr *Init) {
143*700637cbSDimitry Andric if (auto Idx = getGlobal(VD))
144*700637cbSDimitry Andric return Idx;
145*700637cbSDimitry Andric
146*700637cbSDimitry Andric if (auto Idx = createGlobal(VD, Init)) {
147*700637cbSDimitry Andric GlobalIndices[VD] = *Idx;
148*700637cbSDimitry Andric return Idx;
149*700637cbSDimitry Andric }
150*700637cbSDimitry Andric return std::nullopt;
151*700637cbSDimitry Andric }
152*700637cbSDimitry Andric
getOrCreateDummy(const DeclTy & D)153*700637cbSDimitry Andric unsigned Program::getOrCreateDummy(const DeclTy &D) {
154*700637cbSDimitry Andric assert(D);
155*700637cbSDimitry Andric // Dedup blocks since they are immutable and pointers cannot be compared.
156*700637cbSDimitry Andric if (auto It = DummyVariables.find(D.getOpaqueValue());
157*700637cbSDimitry Andric It != DummyVariables.end())
158*700637cbSDimitry Andric return It->second;
159*700637cbSDimitry Andric
160*700637cbSDimitry Andric QualType QT;
161*700637cbSDimitry Andric bool IsWeak = false;
162*700637cbSDimitry Andric if (const auto *E = dyn_cast<const Expr *>(D)) {
163*700637cbSDimitry Andric QT = E->getType();
164*700637cbSDimitry Andric } else {
165*700637cbSDimitry Andric const auto *VD = cast<ValueDecl>(cast<const Decl *>(D));
166*700637cbSDimitry Andric IsWeak = VD->isWeak();
167*700637cbSDimitry Andric QT = VD->getType();
168*700637cbSDimitry Andric if (const auto *RT = QT->getAs<ReferenceType>())
169*700637cbSDimitry Andric QT = RT->getPointeeType();
170*700637cbSDimitry Andric }
171*700637cbSDimitry Andric assert(!QT.isNull());
172*700637cbSDimitry Andric
173*700637cbSDimitry Andric Descriptor *Desc;
174*700637cbSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(QT))
175*700637cbSDimitry Andric Desc = createDescriptor(D, *T, /*SourceTy=*/nullptr, std::nullopt,
176*700637cbSDimitry Andric /*IsConst=*/QT.isConstQualified());
177*700637cbSDimitry Andric else
178*700637cbSDimitry Andric Desc = createDescriptor(D, QT.getTypePtr(), std::nullopt,
179*700637cbSDimitry Andric /*IsConst=*/QT.isConstQualified());
180*700637cbSDimitry Andric if (!Desc)
181*700637cbSDimitry Andric Desc = allocateDescriptor(D);
182*700637cbSDimitry Andric
183*700637cbSDimitry Andric assert(Desc);
184*700637cbSDimitry Andric Desc->makeDummy();
185*700637cbSDimitry Andric
186*700637cbSDimitry Andric assert(Desc->isDummy());
187*700637cbSDimitry Andric
188*700637cbSDimitry Andric // Allocate a block for storage.
189*700637cbSDimitry Andric unsigned I = Globals.size();
190*700637cbSDimitry Andric
191*700637cbSDimitry Andric auto *G = new (Allocator, Desc->getAllocSize())
192*700637cbSDimitry Andric Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true,
193*700637cbSDimitry Andric /*IsExtern=*/false, IsWeak);
194*700637cbSDimitry Andric G->block()->invokeCtor();
195*700637cbSDimitry Andric
196*700637cbSDimitry Andric Globals.push_back(G);
197*700637cbSDimitry Andric DummyVariables[D.getOpaqueValue()] = I;
198*700637cbSDimitry Andric return I;
199*700637cbSDimitry Andric }
200*700637cbSDimitry Andric
createGlobal(const ValueDecl * VD,const Expr * Init)201*700637cbSDimitry Andric std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
202*700637cbSDimitry Andric const Expr *Init) {
203*700637cbSDimitry Andric bool IsStatic, IsExtern;
204*700637cbSDimitry Andric bool IsWeak = VD->isWeak();
205*700637cbSDimitry Andric if (const auto *Var = dyn_cast<VarDecl>(VD)) {
206*700637cbSDimitry Andric IsStatic = Context::shouldBeGloballyIndexed(VD);
207*700637cbSDimitry Andric IsExtern = Var->hasExternalStorage();
208*700637cbSDimitry Andric } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl,
209*700637cbSDimitry Andric TemplateParamObjectDecl>(VD)) {
210*700637cbSDimitry Andric IsStatic = true;
211*700637cbSDimitry Andric IsExtern = false;
212*700637cbSDimitry Andric } else {
213*700637cbSDimitry Andric IsStatic = false;
214*700637cbSDimitry Andric IsExtern = true;
215*700637cbSDimitry Andric }
216*700637cbSDimitry Andric
217*700637cbSDimitry Andric // Register all previous declarations as well. For extern blocks, just replace
218*700637cbSDimitry Andric // the index with the new variable.
219*700637cbSDimitry Andric if (auto Idx =
220*700637cbSDimitry Andric createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init)) {
221*700637cbSDimitry Andric for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
222*700637cbSDimitry Andric unsigned &PIdx = GlobalIndices[P];
223*700637cbSDimitry Andric if (P != VD) {
224*700637cbSDimitry Andric if (Globals[PIdx]->block()->isExtern())
225*700637cbSDimitry Andric Globals[PIdx] = Globals[*Idx];
226*700637cbSDimitry Andric }
227*700637cbSDimitry Andric PIdx = *Idx;
228*700637cbSDimitry Andric }
229*700637cbSDimitry Andric return *Idx;
230*700637cbSDimitry Andric }
231*700637cbSDimitry Andric return std::nullopt;
232*700637cbSDimitry Andric }
233*700637cbSDimitry Andric
createGlobal(const Expr * E)234*700637cbSDimitry Andric std::optional<unsigned> Program::createGlobal(const Expr *E) {
235*700637cbSDimitry Andric if (auto Idx = getGlobal(E))
236*700637cbSDimitry Andric return Idx;
237*700637cbSDimitry Andric if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true,
238*700637cbSDimitry Andric /*isExtern=*/false, /*IsWeak=*/false)) {
239*700637cbSDimitry Andric GlobalIndices[E] = *Idx;
240*700637cbSDimitry Andric return *Idx;
241*700637cbSDimitry Andric }
242*700637cbSDimitry Andric return std::nullopt;
243*700637cbSDimitry Andric }
244*700637cbSDimitry Andric
createGlobal(const DeclTy & D,QualType Ty,bool IsStatic,bool IsExtern,bool IsWeak,const Expr * Init)245*700637cbSDimitry Andric std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
246*700637cbSDimitry Andric bool IsStatic, bool IsExtern,
247*700637cbSDimitry Andric bool IsWeak, const Expr *Init) {
248*700637cbSDimitry Andric // Create a descriptor for the global.
249*700637cbSDimitry Andric Descriptor *Desc;
250*700637cbSDimitry Andric const bool IsConst = Ty.isConstQualified();
251*700637cbSDimitry Andric const bool IsTemporary = D.dyn_cast<const Expr *>();
252*700637cbSDimitry Andric const bool IsVolatile = Ty.isVolatileQualified();
253*700637cbSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(Ty))
254*700637cbSDimitry Andric Desc = createDescriptor(D, *T, nullptr, Descriptor::GlobalMD, IsConst,
255*700637cbSDimitry Andric IsTemporary, /*IsMutable=*/false, IsVolatile);
256*700637cbSDimitry Andric else
257*700637cbSDimitry Andric Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst,
258*700637cbSDimitry Andric IsTemporary, /*IsMutable=*/false, IsVolatile);
259*700637cbSDimitry Andric
260*700637cbSDimitry Andric if (!Desc)
261*700637cbSDimitry Andric return std::nullopt;
262*700637cbSDimitry Andric
263*700637cbSDimitry Andric // Allocate a block for storage.
264*700637cbSDimitry Andric unsigned I = Globals.size();
265*700637cbSDimitry Andric
266*700637cbSDimitry Andric auto *G = new (Allocator, Desc->getAllocSize()) Global(
267*700637cbSDimitry Andric Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern, IsWeak);
268*700637cbSDimitry Andric G->block()->invokeCtor();
269*700637cbSDimitry Andric
270*700637cbSDimitry Andric // Initialize InlineDescriptor fields.
271*700637cbSDimitry Andric auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor();
272*700637cbSDimitry Andric if (!Init)
273*700637cbSDimitry Andric GD->InitState = GlobalInitState::NoInitializer;
274*700637cbSDimitry Andric Globals.push_back(G);
275*700637cbSDimitry Andric
276*700637cbSDimitry Andric return I;
277*700637cbSDimitry Andric }
278*700637cbSDimitry Andric
getFunction(const FunctionDecl * F)279*700637cbSDimitry Andric Function *Program::getFunction(const FunctionDecl *F) {
280*700637cbSDimitry Andric F = F->getCanonicalDecl();
281*700637cbSDimitry Andric assert(F);
282*700637cbSDimitry Andric auto It = Funcs.find(F);
283*700637cbSDimitry Andric return It == Funcs.end() ? nullptr : It->second.get();
284*700637cbSDimitry Andric }
285*700637cbSDimitry Andric
getOrCreateRecord(const RecordDecl * RD)286*700637cbSDimitry Andric Record *Program::getOrCreateRecord(const RecordDecl *RD) {
287*700637cbSDimitry Andric // Use the actual definition as a key.
288*700637cbSDimitry Andric RD = RD->getDefinition();
289*700637cbSDimitry Andric if (!RD)
290*700637cbSDimitry Andric return nullptr;
291*700637cbSDimitry Andric
292*700637cbSDimitry Andric if (!RD->isCompleteDefinition())
293*700637cbSDimitry Andric return nullptr;
294*700637cbSDimitry Andric
295*700637cbSDimitry Andric // Return an existing record if available. Otherwise, we insert nullptr now
296*700637cbSDimitry Andric // and replace that later, so recursive calls to this function with the same
297*700637cbSDimitry Andric // RecordDecl don't run into infinite recursion.
298*700637cbSDimitry Andric auto [It, Inserted] = Records.try_emplace(RD);
299*700637cbSDimitry Andric if (!Inserted)
300*700637cbSDimitry Andric return It->second;
301*700637cbSDimitry Andric
302*700637cbSDimitry Andric // Number of bytes required by fields and base classes.
303*700637cbSDimitry Andric unsigned BaseSize = 0;
304*700637cbSDimitry Andric // Number of bytes required by virtual base.
305*700637cbSDimitry Andric unsigned VirtSize = 0;
306*700637cbSDimitry Andric
307*700637cbSDimitry Andric // Helper to get a base descriptor.
308*700637cbSDimitry Andric auto GetBaseDesc = [this](const RecordDecl *BD,
309*700637cbSDimitry Andric const Record *BR) -> const Descriptor * {
310*700637cbSDimitry Andric if (!BR)
311*700637cbSDimitry Andric return nullptr;
312*700637cbSDimitry Andric return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,
313*700637cbSDimitry Andric /*isTemporary=*/false,
314*700637cbSDimitry Andric /*isMutable=*/false, /*IsVolatile=*/false);
315*700637cbSDimitry Andric };
316*700637cbSDimitry Andric
317*700637cbSDimitry Andric // Reserve space for base classes.
318*700637cbSDimitry Andric Record::BaseList Bases;
319*700637cbSDimitry Andric Record::VirtualBaseList VirtBases;
320*700637cbSDimitry Andric if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
321*700637cbSDimitry Andric for (const CXXBaseSpecifier &Spec : CD->bases()) {
322*700637cbSDimitry Andric if (Spec.isVirtual())
323*700637cbSDimitry Andric continue;
324*700637cbSDimitry Andric
325*700637cbSDimitry Andric // In error cases, the base might not be a RecordType.
326*700637cbSDimitry Andric const auto *RT = Spec.getType()->getAs<RecordType>();
327*700637cbSDimitry Andric if (!RT)
328*700637cbSDimitry Andric return nullptr;
329*700637cbSDimitry Andric const RecordDecl *BD = RT->getDecl();
330*700637cbSDimitry Andric const Record *BR = getOrCreateRecord(BD);
331*700637cbSDimitry Andric
332*700637cbSDimitry Andric const Descriptor *Desc = GetBaseDesc(BD, BR);
333*700637cbSDimitry Andric if (!Desc)
334*700637cbSDimitry Andric return nullptr;
335*700637cbSDimitry Andric
336*700637cbSDimitry Andric BaseSize += align(sizeof(InlineDescriptor));
337*700637cbSDimitry Andric Bases.push_back({BD, BaseSize, Desc, BR});
338*700637cbSDimitry Andric BaseSize += align(BR->getSize());
339*700637cbSDimitry Andric }
340*700637cbSDimitry Andric
341*700637cbSDimitry Andric for (const CXXBaseSpecifier &Spec : CD->vbases()) {
342*700637cbSDimitry Andric const auto *RT = Spec.getType()->getAs<RecordType>();
343*700637cbSDimitry Andric if (!RT)
344*700637cbSDimitry Andric return nullptr;
345*700637cbSDimitry Andric
346*700637cbSDimitry Andric const RecordDecl *BD = RT->getDecl();
347*700637cbSDimitry Andric const Record *BR = getOrCreateRecord(BD);
348*700637cbSDimitry Andric
349*700637cbSDimitry Andric const Descriptor *Desc = GetBaseDesc(BD, BR);
350*700637cbSDimitry Andric if (!Desc)
351*700637cbSDimitry Andric return nullptr;
352*700637cbSDimitry Andric
353*700637cbSDimitry Andric VirtSize += align(sizeof(InlineDescriptor));
354*700637cbSDimitry Andric VirtBases.push_back({BD, VirtSize, Desc, BR});
355*700637cbSDimitry Andric VirtSize += align(BR->getSize());
356*700637cbSDimitry Andric }
357*700637cbSDimitry Andric }
358*700637cbSDimitry Andric
359*700637cbSDimitry Andric // Reserve space for fields.
360*700637cbSDimitry Andric Record::FieldList Fields;
361*700637cbSDimitry Andric for (const FieldDecl *FD : RD->fields()) {
362*700637cbSDimitry Andric FD = FD->getFirstDecl();
363*700637cbSDimitry Andric // Note that we DO create fields and descriptors
364*700637cbSDimitry Andric // for unnamed bitfields here, even though we later ignore
365*700637cbSDimitry Andric // them everywhere. That's so the FieldDecl's getFieldIndex() matches.
366*700637cbSDimitry Andric
367*700637cbSDimitry Andric // Reserve space for the field's descriptor and the offset.
368*700637cbSDimitry Andric BaseSize += align(sizeof(InlineDescriptor));
369*700637cbSDimitry Andric
370*700637cbSDimitry Andric // Classify the field and add its metadata.
371*700637cbSDimitry Andric QualType FT = FD->getType();
372*700637cbSDimitry Andric const bool IsConst = FT.isConstQualified();
373*700637cbSDimitry Andric const bool IsMutable = FD->isMutable();
374*700637cbSDimitry Andric const bool IsVolatile = FT.isVolatileQualified();
375*700637cbSDimitry Andric const Descriptor *Desc;
376*700637cbSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(FT)) {
377*700637cbSDimitry Andric Desc = createDescriptor(FD, *T, nullptr, std::nullopt, IsConst,
378*700637cbSDimitry Andric /*isTemporary=*/false, IsMutable, IsVolatile);
379*700637cbSDimitry Andric } else {
380*700637cbSDimitry Andric Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,
381*700637cbSDimitry Andric /*isTemporary=*/false, IsMutable, IsVolatile);
382*700637cbSDimitry Andric }
383*700637cbSDimitry Andric if (!Desc)
384*700637cbSDimitry Andric return nullptr;
385*700637cbSDimitry Andric Fields.push_back({FD, BaseSize, Desc});
386*700637cbSDimitry Andric BaseSize += align(Desc->getAllocSize());
387*700637cbSDimitry Andric }
388*700637cbSDimitry Andric
389*700637cbSDimitry Andric Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
390*700637cbSDimitry Andric std::move(VirtBases), VirtSize, BaseSize);
391*700637cbSDimitry Andric Records[RD] = R;
392*700637cbSDimitry Andric return R;
393*700637cbSDimitry Andric }
394*700637cbSDimitry Andric
createDescriptor(const DeclTy & D,const Type * Ty,Descriptor::MetadataSize MDSize,bool IsConst,bool IsTemporary,bool IsMutable,bool IsVolatile,const Expr * Init)395*700637cbSDimitry Andric Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
396*700637cbSDimitry Andric Descriptor::MetadataSize MDSize,
397*700637cbSDimitry Andric bool IsConst, bool IsTemporary,
398*700637cbSDimitry Andric bool IsMutable, bool IsVolatile,
399*700637cbSDimitry Andric const Expr *Init) {
400*700637cbSDimitry Andric
401*700637cbSDimitry Andric // Classes and structures.
402*700637cbSDimitry Andric if (const auto *RT = Ty->getAs<RecordType>()) {
403*700637cbSDimitry Andric if (const auto *Record = getOrCreateRecord(RT->getDecl()))
404*700637cbSDimitry Andric return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
405*700637cbSDimitry Andric IsMutable, IsVolatile);
406*700637cbSDimitry Andric return allocateDescriptor(D, MDSize);
407*700637cbSDimitry Andric }
408*700637cbSDimitry Andric
409*700637cbSDimitry Andric // Arrays.
410*700637cbSDimitry Andric if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) {
411*700637cbSDimitry Andric QualType ElemTy = ArrayType->getElementType();
412*700637cbSDimitry Andric // Array of well-known bounds.
413*700637cbSDimitry Andric if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
414*700637cbSDimitry Andric size_t NumElems = CAT->getZExtSize();
415*700637cbSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
416*700637cbSDimitry Andric // Arrays of primitives.
417*700637cbSDimitry Andric unsigned ElemSize = primSize(*T);
418*700637cbSDimitry Andric if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
419*700637cbSDimitry Andric return {};
420*700637cbSDimitry Andric }
421*700637cbSDimitry Andric return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary,
422*700637cbSDimitry Andric IsMutable);
423*700637cbSDimitry Andric } else {
424*700637cbSDimitry Andric // Arrays of composites. In this case, the array is a list of pointers,
425*700637cbSDimitry Andric // followed by the actual elements.
426*700637cbSDimitry Andric const Descriptor *ElemDesc = createDescriptor(
427*700637cbSDimitry Andric D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
428*700637cbSDimitry Andric if (!ElemDesc)
429*700637cbSDimitry Andric return nullptr;
430*700637cbSDimitry Andric unsigned ElemSize = ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
431*700637cbSDimitry Andric if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
432*700637cbSDimitry Andric return {};
433*700637cbSDimitry Andric return allocateDescriptor(D, Ty, ElemDesc, MDSize, NumElems, IsConst,
434*700637cbSDimitry Andric IsTemporary, IsMutable);
435*700637cbSDimitry Andric }
436*700637cbSDimitry Andric }
437*700637cbSDimitry Andric
438*700637cbSDimitry Andric // Array of unknown bounds - cannot be accessed and pointer arithmetic
439*700637cbSDimitry Andric // is forbidden on pointers to such objects.
440*700637cbSDimitry Andric if (isa<IncompleteArrayType>(ArrayType) ||
441*700637cbSDimitry Andric isa<VariableArrayType>(ArrayType)) {
442*700637cbSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
443*700637cbSDimitry Andric return allocateDescriptor(D, *T, MDSize, IsConst, IsTemporary,
444*700637cbSDimitry Andric Descriptor::UnknownSize{});
445*700637cbSDimitry Andric } else {
446*700637cbSDimitry Andric const Descriptor *Desc = createDescriptor(
447*700637cbSDimitry Andric D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
448*700637cbSDimitry Andric if (!Desc)
449*700637cbSDimitry Andric return nullptr;
450*700637cbSDimitry Andric return allocateDescriptor(D, Desc, MDSize, IsTemporary,
451*700637cbSDimitry Andric Descriptor::UnknownSize{});
452*700637cbSDimitry Andric }
453*700637cbSDimitry Andric }
454*700637cbSDimitry Andric }
455*700637cbSDimitry Andric
456*700637cbSDimitry Andric // Atomic types.
457*700637cbSDimitry Andric if (const auto *AT = Ty->getAs<AtomicType>()) {
458*700637cbSDimitry Andric const Type *InnerTy = AT->getValueType().getTypePtr();
459*700637cbSDimitry Andric return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,
460*700637cbSDimitry Andric IsMutable);
461*700637cbSDimitry Andric }
462*700637cbSDimitry Andric
463*700637cbSDimitry Andric // Complex types - represented as arrays of elements.
464*700637cbSDimitry Andric if (const auto *CT = Ty->getAs<ComplexType>()) {
465*700637cbSDimitry Andric std::optional<PrimType> ElemTy = Ctx.classify(CT->getElementType());
466*700637cbSDimitry Andric if (!ElemTy)
467*700637cbSDimitry Andric return nullptr;
468*700637cbSDimitry Andric
469*700637cbSDimitry Andric return allocateDescriptor(D, *ElemTy, MDSize, 2, IsConst, IsTemporary,
470*700637cbSDimitry Andric IsMutable);
471*700637cbSDimitry Andric }
472*700637cbSDimitry Andric
473*700637cbSDimitry Andric // Same with vector types.
474*700637cbSDimitry Andric if (const auto *VT = Ty->getAs<VectorType>()) {
475*700637cbSDimitry Andric std::optional<PrimType> ElemTy = Ctx.classify(VT->getElementType());
476*700637cbSDimitry Andric if (!ElemTy)
477*700637cbSDimitry Andric return nullptr;
478*700637cbSDimitry Andric
479*700637cbSDimitry Andric return allocateDescriptor(D, *ElemTy, MDSize, VT->getNumElements(), IsConst,
480*700637cbSDimitry Andric IsTemporary, IsMutable);
481*700637cbSDimitry Andric }
482*700637cbSDimitry Andric
483*700637cbSDimitry Andric return nullptr;
484*700637cbSDimitry Andric }
485