xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Program.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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