xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Descriptor.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===--- Descriptor.cpp - Types 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 "Descriptor.h"
10*700637cbSDimitry Andric #include "Boolean.h"
11*700637cbSDimitry Andric #include "FixedPoint.h"
12*700637cbSDimitry Andric #include "Floating.h"
13*700637cbSDimitry Andric #include "IntegralAP.h"
14*700637cbSDimitry Andric #include "MemberPointer.h"
15*700637cbSDimitry Andric #include "Pointer.h"
16*700637cbSDimitry Andric #include "PrimType.h"
17*700637cbSDimitry Andric #include "Record.h"
18*700637cbSDimitry Andric #include "Source.h"
19*700637cbSDimitry Andric #include "clang/AST/ExprCXX.h"
20*700637cbSDimitry Andric 
21*700637cbSDimitry Andric using namespace clang;
22*700637cbSDimitry Andric using namespace clang::interp;
23*700637cbSDimitry Andric 
24*700637cbSDimitry Andric template <typename T>
ctorTy(Block *,std::byte * Ptr,bool,bool,bool,bool,bool,const Descriptor *)25*700637cbSDimitry Andric static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
26*700637cbSDimitry Andric                    const Descriptor *) {
27*700637cbSDimitry Andric   new (Ptr) T();
28*700637cbSDimitry Andric }
29*700637cbSDimitry Andric 
30*700637cbSDimitry Andric template <typename T>
dtorTy(Block *,std::byte * Ptr,const Descriptor *)31*700637cbSDimitry Andric static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
32*700637cbSDimitry Andric   reinterpret_cast<T *>(Ptr)->~T();
33*700637cbSDimitry Andric }
34*700637cbSDimitry Andric 
35*700637cbSDimitry Andric template <typename T>
moveTy(Block *,std::byte * Src,std::byte * Dst,const Descriptor *)36*700637cbSDimitry Andric static void moveTy(Block *, std::byte *Src, std::byte *Dst,
37*700637cbSDimitry Andric                    const Descriptor *) {
38*700637cbSDimitry Andric   auto *SrcPtr = reinterpret_cast<T *>(Src);
39*700637cbSDimitry Andric   auto *DstPtr = reinterpret_cast<T *>(Dst);
40*700637cbSDimitry Andric   new (DstPtr) T(std::move(*SrcPtr));
41*700637cbSDimitry Andric }
42*700637cbSDimitry Andric 
43*700637cbSDimitry Andric template <typename T>
ctorArrayTy(Block *,std::byte * Ptr,bool,bool,bool,bool,bool,const Descriptor * D)44*700637cbSDimitry Andric static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
45*700637cbSDimitry Andric                         const Descriptor *D) {
46*700637cbSDimitry Andric   new (Ptr) InitMapPtr(std::nullopt);
47*700637cbSDimitry Andric 
48*700637cbSDimitry Andric   Ptr += sizeof(InitMapPtr);
49*700637cbSDimitry Andric   for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
50*700637cbSDimitry Andric     new (&reinterpret_cast<T *>(Ptr)[I]) T();
51*700637cbSDimitry Andric   }
52*700637cbSDimitry Andric }
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric template <typename T>
dtorArrayTy(Block *,std::byte * Ptr,const Descriptor * D)55*700637cbSDimitry Andric static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
56*700637cbSDimitry Andric   InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
57*700637cbSDimitry Andric 
58*700637cbSDimitry Andric   if (IMP)
59*700637cbSDimitry Andric     IMP = std::nullopt;
60*700637cbSDimitry Andric   Ptr += sizeof(InitMapPtr);
61*700637cbSDimitry Andric   for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
62*700637cbSDimitry Andric     reinterpret_cast<T *>(Ptr)[I].~T();
63*700637cbSDimitry Andric   }
64*700637cbSDimitry Andric }
65*700637cbSDimitry Andric 
66*700637cbSDimitry Andric template <typename T>
moveArrayTy(Block *,std::byte * Src,std::byte * Dst,const Descriptor * D)67*700637cbSDimitry Andric static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst,
68*700637cbSDimitry Andric                         const Descriptor *D) {
69*700637cbSDimitry Andric   InitMapPtr &SrcIMP = *reinterpret_cast<InitMapPtr *>(Src);
70*700637cbSDimitry Andric   if (SrcIMP) {
71*700637cbSDimitry Andric     // We only ever invoke the moveFunc when moving block contents to a
72*700637cbSDimitry Andric     // DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here.
73*700637cbSDimitry Andric     SrcIMP = std::nullopt;
74*700637cbSDimitry Andric   }
75*700637cbSDimitry Andric   Src += sizeof(InitMapPtr);
76*700637cbSDimitry Andric   Dst += sizeof(InitMapPtr);
77*700637cbSDimitry Andric   for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
78*700637cbSDimitry Andric     auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
79*700637cbSDimitry Andric     auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
80*700637cbSDimitry Andric     new (DstPtr) T(std::move(*SrcPtr));
81*700637cbSDimitry Andric   }
82*700637cbSDimitry Andric }
83*700637cbSDimitry Andric 
ctorArrayDesc(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool InUnion,const Descriptor * D)84*700637cbSDimitry Andric static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
85*700637cbSDimitry Andric                           bool IsMutable, bool IsVolatile, bool IsActive,
86*700637cbSDimitry Andric                           bool InUnion, const Descriptor *D) {
87*700637cbSDimitry Andric   const unsigned NumElems = D->getNumElems();
88*700637cbSDimitry Andric   const unsigned ElemSize =
89*700637cbSDimitry Andric       D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
90*700637cbSDimitry Andric 
91*700637cbSDimitry Andric   unsigned ElemOffset = 0;
92*700637cbSDimitry Andric   for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
93*700637cbSDimitry Andric     auto *ElemPtr = Ptr + ElemOffset;
94*700637cbSDimitry Andric     auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
95*700637cbSDimitry Andric     auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
96*700637cbSDimitry Andric     auto *SD = D->ElemDesc;
97*700637cbSDimitry Andric 
98*700637cbSDimitry Andric     Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
99*700637cbSDimitry Andric     Desc->Desc = SD;
100*700637cbSDimitry Andric     Desc->IsInitialized = true;
101*700637cbSDimitry Andric     Desc->IsBase = false;
102*700637cbSDimitry Andric     Desc->IsActive = IsActive;
103*700637cbSDimitry Andric     Desc->IsConst = IsConst || D->IsConst;
104*700637cbSDimitry Andric     Desc->IsFieldMutable = IsMutable || D->IsMutable;
105*700637cbSDimitry Andric     Desc->InUnion = InUnion;
106*700637cbSDimitry Andric     Desc->IsArrayElement = true;
107*700637cbSDimitry Andric     Desc->IsVolatile = IsVolatile;
108*700637cbSDimitry Andric 
109*700637cbSDimitry Andric     if (auto Fn = D->ElemDesc->CtorFn)
110*700637cbSDimitry Andric       Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,
111*700637cbSDimitry Andric          Desc->InUnion || SD->isUnion(), D->ElemDesc);
112*700637cbSDimitry Andric   }
113*700637cbSDimitry Andric }
114*700637cbSDimitry Andric 
dtorArrayDesc(Block * B,std::byte * Ptr,const Descriptor * D)115*700637cbSDimitry Andric static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
116*700637cbSDimitry Andric   const unsigned NumElems = D->getNumElems();
117*700637cbSDimitry Andric   const unsigned ElemSize =
118*700637cbSDimitry Andric       D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
119*700637cbSDimitry Andric 
120*700637cbSDimitry Andric   unsigned ElemOffset = 0;
121*700637cbSDimitry Andric   for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
122*700637cbSDimitry Andric     auto *ElemPtr = Ptr + ElemOffset;
123*700637cbSDimitry Andric     auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
124*700637cbSDimitry Andric     auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
125*700637cbSDimitry Andric     if (auto Fn = D->ElemDesc->DtorFn)
126*700637cbSDimitry Andric       Fn(B, ElemLoc, D->ElemDesc);
127*700637cbSDimitry Andric   }
128*700637cbSDimitry Andric }
129*700637cbSDimitry Andric 
moveArrayDesc(Block * B,std::byte * Src,std::byte * Dst,const Descriptor * D)130*700637cbSDimitry Andric static void moveArrayDesc(Block *B, std::byte *Src, std::byte *Dst,
131*700637cbSDimitry Andric                           const Descriptor *D) {
132*700637cbSDimitry Andric   const unsigned NumElems = D->getNumElems();
133*700637cbSDimitry Andric   const unsigned ElemSize =
134*700637cbSDimitry Andric       D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
135*700637cbSDimitry Andric 
136*700637cbSDimitry Andric   unsigned ElemOffset = 0;
137*700637cbSDimitry Andric   for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
138*700637cbSDimitry Andric     auto *SrcPtr = Src + ElemOffset;
139*700637cbSDimitry Andric     auto *DstPtr = Dst + ElemOffset;
140*700637cbSDimitry Andric 
141*700637cbSDimitry Andric     auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);
142*700637cbSDimitry Andric     auto *SrcElemLoc = reinterpret_cast<std::byte *>(SrcDesc + 1);
143*700637cbSDimitry Andric     auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
144*700637cbSDimitry Andric     auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1);
145*700637cbSDimitry Andric 
146*700637cbSDimitry Andric     *DstDesc = *SrcDesc;
147*700637cbSDimitry Andric     if (auto Fn = D->ElemDesc->MoveFn)
148*700637cbSDimitry Andric       Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
149*700637cbSDimitry Andric   }
150*700637cbSDimitry Andric }
151*700637cbSDimitry Andric 
initField(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool IsUnionField,bool InUnion,const Descriptor * D,unsigned FieldOffset)152*700637cbSDimitry Andric static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
153*700637cbSDimitry Andric                       bool IsVolatile, bool IsActive, bool IsUnionField,
154*700637cbSDimitry Andric                       bool InUnion, const Descriptor *D, unsigned FieldOffset) {
155*700637cbSDimitry Andric   auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
156*700637cbSDimitry Andric   Desc->Offset = FieldOffset;
157*700637cbSDimitry Andric   Desc->Desc = D;
158*700637cbSDimitry Andric   Desc->IsInitialized = D->IsArray;
159*700637cbSDimitry Andric   Desc->IsBase = false;
160*700637cbSDimitry Andric   Desc->IsActive = IsActive && !IsUnionField;
161*700637cbSDimitry Andric   Desc->InUnion = InUnion;
162*700637cbSDimitry Andric   Desc->IsConst = IsConst || D->IsConst;
163*700637cbSDimitry Andric   Desc->IsFieldMutable = IsMutable || D->IsMutable;
164*700637cbSDimitry Andric   Desc->IsVolatile = IsVolatile || D->IsVolatile;
165*700637cbSDimitry Andric 
166*700637cbSDimitry Andric   if (auto Fn = D->CtorFn)
167*700637cbSDimitry Andric     Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
168*700637cbSDimitry Andric        Desc->IsVolatile, Desc->IsActive, InUnion || D->isUnion(), D);
169*700637cbSDimitry Andric }
170*700637cbSDimitry Andric 
initBase(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool InUnion,const Descriptor * D,unsigned FieldOffset,bool IsVirtualBase)171*700637cbSDimitry Andric static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
172*700637cbSDimitry Andric                      bool IsVolatile, bool IsActive, bool InUnion,
173*700637cbSDimitry Andric                      const Descriptor *D, unsigned FieldOffset,
174*700637cbSDimitry Andric                      bool IsVirtualBase) {
175*700637cbSDimitry Andric   assert(D);
176*700637cbSDimitry Andric   assert(D->ElemRecord);
177*700637cbSDimitry Andric   assert(!D->ElemRecord->isUnion()); // Unions cannot be base classes.
178*700637cbSDimitry Andric 
179*700637cbSDimitry Andric   auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
180*700637cbSDimitry Andric   Desc->Offset = FieldOffset;
181*700637cbSDimitry Andric   Desc->Desc = D;
182*700637cbSDimitry Andric   Desc->IsInitialized = D->IsArray;
183*700637cbSDimitry Andric   Desc->IsBase = true;
184*700637cbSDimitry Andric   Desc->IsVirtualBase = IsVirtualBase;
185*700637cbSDimitry Andric   Desc->IsActive = IsActive && !InUnion;
186*700637cbSDimitry Andric   Desc->IsConst = IsConst || D->IsConst;
187*700637cbSDimitry Andric   Desc->IsFieldMutable = IsMutable || D->IsMutable;
188*700637cbSDimitry Andric   Desc->InUnion = InUnion;
189*700637cbSDimitry Andric   Desc->IsVolatile = false;
190*700637cbSDimitry Andric 
191*700637cbSDimitry Andric   for (const auto &V : D->ElemRecord->bases())
192*700637cbSDimitry Andric     initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
193*700637cbSDimitry Andric              InUnion, V.Desc, V.Offset, false);
194*700637cbSDimitry Andric   for (const auto &F : D->ElemRecord->fields())
195*700637cbSDimitry Andric     initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
196*700637cbSDimitry Andric               InUnion, InUnion, F.Desc, F.Offset);
197*700637cbSDimitry Andric }
198*700637cbSDimitry Andric 
ctorRecord(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool InUnion,const Descriptor * D)199*700637cbSDimitry Andric static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
200*700637cbSDimitry Andric                        bool IsVolatile, bool IsActive, bool InUnion,
201*700637cbSDimitry Andric                        const Descriptor *D) {
202*700637cbSDimitry Andric   for (const auto &V : D->ElemRecord->bases())
203*700637cbSDimitry Andric     initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
204*700637cbSDimitry Andric              V.Offset,
205*700637cbSDimitry Andric              /*IsVirtualBase=*/false);
206*700637cbSDimitry Andric   for (const auto &F : D->ElemRecord->fields()) {
207*700637cbSDimitry Andric     bool IsUnionField = D->isUnion();
208*700637cbSDimitry Andric     initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,
209*700637cbSDimitry Andric               InUnion || IsUnionField, F.Desc, F.Offset);
210*700637cbSDimitry Andric   }
211*700637cbSDimitry Andric   for (const auto &V : D->ElemRecord->virtual_bases())
212*700637cbSDimitry Andric     initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
213*700637cbSDimitry Andric              V.Offset,
214*700637cbSDimitry Andric              /*IsVirtualBase=*/true);
215*700637cbSDimitry Andric }
216*700637cbSDimitry Andric 
destroyField(Block * B,std::byte * Ptr,const Descriptor * D,unsigned FieldOffset)217*700637cbSDimitry Andric static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,
218*700637cbSDimitry Andric                          unsigned FieldOffset) {
219*700637cbSDimitry Andric   if (auto Fn = D->DtorFn)
220*700637cbSDimitry Andric     Fn(B, Ptr + FieldOffset, D);
221*700637cbSDimitry Andric }
222*700637cbSDimitry Andric 
destroyBase(Block * B,std::byte * Ptr,const Descriptor * D,unsigned FieldOffset)223*700637cbSDimitry Andric static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D,
224*700637cbSDimitry Andric                         unsigned FieldOffset) {
225*700637cbSDimitry Andric   assert(D);
226*700637cbSDimitry Andric   assert(D->ElemRecord);
227*700637cbSDimitry Andric 
228*700637cbSDimitry Andric   for (const auto &V : D->ElemRecord->bases())
229*700637cbSDimitry Andric     destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset);
230*700637cbSDimitry Andric   for (const auto &F : D->ElemRecord->fields())
231*700637cbSDimitry Andric     destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset);
232*700637cbSDimitry Andric }
233*700637cbSDimitry Andric 
dtorRecord(Block * B,std::byte * Ptr,const Descriptor * D)234*700637cbSDimitry Andric static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
235*700637cbSDimitry Andric   for (const auto &F : D->ElemRecord->bases())
236*700637cbSDimitry Andric     destroyBase(B, Ptr, F.Desc, F.Offset);
237*700637cbSDimitry Andric   for (const auto &F : D->ElemRecord->fields())
238*700637cbSDimitry Andric     destroyField(B, Ptr, F.Desc, F.Offset);
239*700637cbSDimitry Andric   for (const auto &F : D->ElemRecord->virtual_bases())
240*700637cbSDimitry Andric     destroyBase(B, Ptr, F.Desc, F.Offset);
241*700637cbSDimitry Andric }
242*700637cbSDimitry Andric 
moveRecord(Block * B,std::byte * Src,std::byte * Dst,const Descriptor * D)243*700637cbSDimitry Andric static void moveRecord(Block *B, std::byte *Src, std::byte *Dst,
244*700637cbSDimitry Andric                        const Descriptor *D) {
245*700637cbSDimitry Andric   assert(D);
246*700637cbSDimitry Andric   assert(D->ElemRecord);
247*700637cbSDimitry Andric 
248*700637cbSDimitry Andric   // FIXME: Code duplication.
249*700637cbSDimitry Andric   for (const auto &F : D->ElemRecord->fields()) {
250*700637cbSDimitry Andric     auto FieldOffset = F.Offset;
251*700637cbSDimitry Andric     const auto *SrcDesc =
252*700637cbSDimitry Andric         reinterpret_cast<const InlineDescriptor *>(Src + FieldOffset) - 1;
253*700637cbSDimitry Andric     auto *DestDesc =
254*700637cbSDimitry Andric         reinterpret_cast<InlineDescriptor *>(Dst + FieldOffset) - 1;
255*700637cbSDimitry Andric     std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));
256*700637cbSDimitry Andric 
257*700637cbSDimitry Andric     if (auto Fn = F.Desc->MoveFn)
258*700637cbSDimitry Andric       Fn(B, Src + FieldOffset, Dst + FieldOffset, F.Desc);
259*700637cbSDimitry Andric   }
260*700637cbSDimitry Andric 
261*700637cbSDimitry Andric   for (const auto &Base : D->ElemRecord->bases()) {
262*700637cbSDimitry Andric     auto BaseOffset = Base.Offset;
263*700637cbSDimitry Andric     const auto *SrcDesc =
264*700637cbSDimitry Andric         reinterpret_cast<const InlineDescriptor *>(Src + BaseOffset) - 1;
265*700637cbSDimitry Andric     auto *DestDesc = reinterpret_cast<InlineDescriptor *>(Dst + BaseOffset) - 1;
266*700637cbSDimitry Andric     std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));
267*700637cbSDimitry Andric 
268*700637cbSDimitry Andric     if (auto Fn = Base.Desc->MoveFn)
269*700637cbSDimitry Andric       Fn(B, Src + BaseOffset, Dst + BaseOffset, Base.Desc);
270*700637cbSDimitry Andric   }
271*700637cbSDimitry Andric 
272*700637cbSDimitry Andric   for (const auto &VBase : D->ElemRecord->virtual_bases()) {
273*700637cbSDimitry Andric     auto VBaseOffset = VBase.Offset;
274*700637cbSDimitry Andric     const auto *SrcDesc =
275*700637cbSDimitry Andric         reinterpret_cast<const InlineDescriptor *>(Src + VBaseOffset) - 1;
276*700637cbSDimitry Andric     auto *DestDesc =
277*700637cbSDimitry Andric         reinterpret_cast<InlineDescriptor *>(Dst + VBaseOffset) - 1;
278*700637cbSDimitry Andric     std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));
279*700637cbSDimitry Andric   }
280*700637cbSDimitry Andric }
281*700637cbSDimitry Andric 
getCtorPrim(PrimType Type)282*700637cbSDimitry Andric static BlockCtorFn getCtorPrim(PrimType Type) {
283*700637cbSDimitry Andric   // Floating types are special. They are primitives, but need their
284*700637cbSDimitry Andric   // constructor called.
285*700637cbSDimitry Andric   if (Type == PT_Float)
286*700637cbSDimitry Andric     return ctorTy<PrimConv<PT_Float>::T>;
287*700637cbSDimitry Andric   if (Type == PT_IntAP)
288*700637cbSDimitry Andric     return ctorTy<PrimConv<PT_IntAP>::T>;
289*700637cbSDimitry Andric   if (Type == PT_IntAPS)
290*700637cbSDimitry Andric     return ctorTy<PrimConv<PT_IntAPS>::T>;
291*700637cbSDimitry Andric   if (Type == PT_MemberPtr)
292*700637cbSDimitry Andric     return ctorTy<PrimConv<PT_MemberPtr>::T>;
293*700637cbSDimitry Andric 
294*700637cbSDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
295*700637cbSDimitry Andric }
296*700637cbSDimitry Andric 
getDtorPrim(PrimType Type)297*700637cbSDimitry Andric static BlockDtorFn getDtorPrim(PrimType Type) {
298*700637cbSDimitry Andric   // Floating types are special. They are primitives, but need their
299*700637cbSDimitry Andric   // destructor called, since they might allocate memory.
300*700637cbSDimitry Andric   if (Type == PT_Float)
301*700637cbSDimitry Andric     return dtorTy<PrimConv<PT_Float>::T>;
302*700637cbSDimitry Andric   if (Type == PT_IntAP)
303*700637cbSDimitry Andric     return dtorTy<PrimConv<PT_IntAP>::T>;
304*700637cbSDimitry Andric   if (Type == PT_IntAPS)
305*700637cbSDimitry Andric     return dtorTy<PrimConv<PT_IntAPS>::T>;
306*700637cbSDimitry Andric   if (Type == PT_MemberPtr)
307*700637cbSDimitry Andric     return dtorTy<PrimConv<PT_MemberPtr>::T>;
308*700637cbSDimitry Andric 
309*700637cbSDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
310*700637cbSDimitry Andric }
311*700637cbSDimitry Andric 
getMovePrim(PrimType Type)312*700637cbSDimitry Andric static BlockMoveFn getMovePrim(PrimType Type) {
313*700637cbSDimitry Andric   if (Type == PT_Float)
314*700637cbSDimitry Andric     return moveTy<PrimConv<PT_Float>::T>;
315*700637cbSDimitry Andric   if (Type == PT_IntAP)
316*700637cbSDimitry Andric     return moveTy<PrimConv<PT_IntAP>::T>;
317*700637cbSDimitry Andric   if (Type == PT_IntAPS)
318*700637cbSDimitry Andric     return moveTy<PrimConv<PT_IntAPS>::T>;
319*700637cbSDimitry Andric   if (Type == PT_MemberPtr)
320*700637cbSDimitry Andric     return moveTy<PrimConv<PT_MemberPtr>::T>;
321*700637cbSDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
322*700637cbSDimitry Andric }
323*700637cbSDimitry Andric 
getCtorArrayPrim(PrimType Type)324*700637cbSDimitry Andric static BlockCtorFn getCtorArrayPrim(PrimType Type) {
325*700637cbSDimitry Andric   TYPE_SWITCH(Type, return ctorArrayTy<T>);
326*700637cbSDimitry Andric   llvm_unreachable("unknown Expr");
327*700637cbSDimitry Andric }
328*700637cbSDimitry Andric 
getDtorArrayPrim(PrimType Type)329*700637cbSDimitry Andric static BlockDtorFn getDtorArrayPrim(PrimType Type) {
330*700637cbSDimitry Andric   TYPE_SWITCH(Type, return dtorArrayTy<T>);
331*700637cbSDimitry Andric   llvm_unreachable("unknown Expr");
332*700637cbSDimitry Andric }
333*700637cbSDimitry Andric 
getMoveArrayPrim(PrimType Type)334*700637cbSDimitry Andric static BlockMoveFn getMoveArrayPrim(PrimType Type) {
335*700637cbSDimitry Andric   TYPE_SWITCH(Type, return moveArrayTy<T>);
336*700637cbSDimitry Andric   llvm_unreachable("unknown Expr");
337*700637cbSDimitry Andric }
338*700637cbSDimitry Andric 
339*700637cbSDimitry Andric /// Primitives.
Descriptor(const DeclTy & D,const Type * SourceTy,PrimType Type,MetadataSize MD,bool IsConst,bool IsTemporary,bool IsMutable,bool IsVolatile)340*700637cbSDimitry Andric Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,
341*700637cbSDimitry Andric                        MetadataSize MD, bool IsConst, bool IsTemporary,
342*700637cbSDimitry Andric                        bool IsMutable, bool IsVolatile)
343*700637cbSDimitry Andric     : Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),
344*700637cbSDimitry Andric       MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),
345*700637cbSDimitry Andric       IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
346*700637cbSDimitry Andric       IsVolatile(IsVolatile), CtorFn(getCtorPrim(Type)),
347*700637cbSDimitry Andric       DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {
348*700637cbSDimitry Andric   assert(AllocSize >= Size);
349*700637cbSDimitry Andric   assert(Source && "Missing source");
350*700637cbSDimitry Andric }
351*700637cbSDimitry Andric 
352*700637cbSDimitry Andric /// Primitive arrays.
Descriptor(const DeclTy & D,PrimType Type,MetadataSize MD,size_t NumElems,bool IsConst,bool IsTemporary,bool IsMutable)353*700637cbSDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
354*700637cbSDimitry Andric                        size_t NumElems, bool IsConst, bool IsTemporary,
355*700637cbSDimitry Andric                        bool IsMutable)
356*700637cbSDimitry Andric     : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
357*700637cbSDimitry Andric       MDSize(MD.value_or(0)),
358*700637cbSDimitry Andric       AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),
359*700637cbSDimitry Andric       IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
360*700637cbSDimitry Andric       IsArray(true), CtorFn(getCtorArrayPrim(Type)),
361*700637cbSDimitry Andric       DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
362*700637cbSDimitry Andric   assert(Source && "Missing source");
363*700637cbSDimitry Andric   assert(NumElems <= (MaxArrayElemBytes / ElemSize));
364*700637cbSDimitry Andric }
365*700637cbSDimitry Andric 
366*700637cbSDimitry Andric /// Primitive unknown-size arrays.
Descriptor(const DeclTy & D,PrimType Type,MetadataSize MD,bool IsTemporary,bool IsConst,UnknownSize)367*700637cbSDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
368*700637cbSDimitry Andric                        bool IsTemporary, bool IsConst, UnknownSize)
369*700637cbSDimitry Andric     : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
370*700637cbSDimitry Andric       MDSize(MD.value_or(0)),
371*700637cbSDimitry Andric       AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),
372*700637cbSDimitry Andric       IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary),
373*700637cbSDimitry Andric       IsArray(true), CtorFn(getCtorArrayPrim(Type)),
374*700637cbSDimitry Andric       DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
375*700637cbSDimitry Andric   assert(Source && "Missing source");
376*700637cbSDimitry Andric }
377*700637cbSDimitry Andric 
378*700637cbSDimitry Andric /// Arrays of composite elements.
Descriptor(const DeclTy & D,const Type * SourceTy,const Descriptor * Elem,MetadataSize MD,unsigned NumElems,bool IsConst,bool IsTemporary,bool IsMutable)379*700637cbSDimitry Andric Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy,
380*700637cbSDimitry Andric                        const Descriptor *Elem, MetadataSize MD,
381*700637cbSDimitry Andric                        unsigned NumElems, bool IsConst, bool IsTemporary,
382*700637cbSDimitry Andric                        bool IsMutable)
383*700637cbSDimitry Andric     : Source(D), SourceType(SourceTy),
384*700637cbSDimitry Andric       ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
385*700637cbSDimitry Andric       Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
386*700637cbSDimitry Andric       AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
387*700637cbSDimitry Andric       ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
388*700637cbSDimitry Andric       IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
389*700637cbSDimitry Andric       DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
390*700637cbSDimitry Andric   assert(Source && "Missing source");
391*700637cbSDimitry Andric }
392*700637cbSDimitry Andric 
393*700637cbSDimitry Andric /// Unknown-size arrays of composite elements.
Descriptor(const DeclTy & D,const Descriptor * Elem,MetadataSize MD,bool IsTemporary,UnknownSize)394*700637cbSDimitry Andric Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
395*700637cbSDimitry Andric                        bool IsTemporary, UnknownSize)
396*700637cbSDimitry Andric     : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
397*700637cbSDimitry Andric       Size(UnknownSizeMark), MDSize(MD.value_or(0)),
398*700637cbSDimitry Andric       AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),
399*700637cbSDimitry Andric       IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
400*700637cbSDimitry Andric       CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
401*700637cbSDimitry Andric   assert(Source && "Missing source");
402*700637cbSDimitry Andric }
403*700637cbSDimitry Andric 
404*700637cbSDimitry Andric /// Composite records.
Descriptor(const DeclTy & D,const Record * R,MetadataSize MD,bool IsConst,bool IsTemporary,bool IsMutable,bool IsVolatile)405*700637cbSDimitry Andric Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
406*700637cbSDimitry Andric                        bool IsConst, bool IsTemporary, bool IsMutable,
407*700637cbSDimitry Andric                        bool IsVolatile)
408*700637cbSDimitry Andric     : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
409*700637cbSDimitry Andric       Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
410*700637cbSDimitry Andric       ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
411*700637cbSDimitry Andric       IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(ctorRecord),
412*700637cbSDimitry Andric       DtorFn(dtorRecord), MoveFn(moveRecord) {
413*700637cbSDimitry Andric   assert(Source && "Missing source");
414*700637cbSDimitry Andric }
415*700637cbSDimitry Andric 
416*700637cbSDimitry Andric /// Dummy.
Descriptor(const DeclTy & D,MetadataSize MD)417*700637cbSDimitry Andric Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
418*700637cbSDimitry Andric     : Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)),
419*700637cbSDimitry Andric       AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
420*700637cbSDimitry Andric       IsTemporary(false), IsDummy(true) {
421*700637cbSDimitry Andric   assert(Source && "Missing source");
422*700637cbSDimitry Andric }
423*700637cbSDimitry Andric 
getType() const424*700637cbSDimitry Andric QualType Descriptor::getType() const {
425*700637cbSDimitry Andric   if (SourceType)
426*700637cbSDimitry Andric     return QualType(SourceType, 0);
427*700637cbSDimitry Andric   if (const auto *D = asValueDecl())
428*700637cbSDimitry Andric     return D->getType();
429*700637cbSDimitry Andric   if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))
430*700637cbSDimitry Andric     return QualType(T->getTypeForDecl(), 0);
431*700637cbSDimitry Andric 
432*700637cbSDimitry Andric   // The Source sometimes has a different type than the once
433*700637cbSDimitry Andric   // we really save. Try to consult the Record first.
434*700637cbSDimitry Andric   if (isRecord())
435*700637cbSDimitry Andric     return QualType(ElemRecord->getDecl()->getTypeForDecl(), 0);
436*700637cbSDimitry Andric   if (const auto *E = asExpr())
437*700637cbSDimitry Andric     return E->getType();
438*700637cbSDimitry Andric   llvm_unreachable("Invalid descriptor type");
439*700637cbSDimitry Andric }
440*700637cbSDimitry Andric 
getElemQualType() const441*700637cbSDimitry Andric QualType Descriptor::getElemQualType() const {
442*700637cbSDimitry Andric   assert(isArray());
443*700637cbSDimitry Andric   QualType T = getType();
444*700637cbSDimitry Andric   if (T->isPointerOrReferenceType())
445*700637cbSDimitry Andric     T = T->getPointeeType();
446*700637cbSDimitry Andric 
447*700637cbSDimitry Andric   if (const auto *AT = T->getAsArrayTypeUnsafe()) {
448*700637cbSDimitry Andric     // For primitive arrays, we don't save a QualType at all,
449*700637cbSDimitry Andric     // just a PrimType. Try to figure out the QualType here.
450*700637cbSDimitry Andric     if (isPrimitiveArray()) {
451*700637cbSDimitry Andric       while (T->isArrayType())
452*700637cbSDimitry Andric         T = T->getAsArrayTypeUnsafe()->getElementType();
453*700637cbSDimitry Andric       return T;
454*700637cbSDimitry Andric     }
455*700637cbSDimitry Andric     return AT->getElementType();
456*700637cbSDimitry Andric   }
457*700637cbSDimitry Andric   if (const auto *CT = T->getAs<ComplexType>())
458*700637cbSDimitry Andric     return CT->getElementType();
459*700637cbSDimitry Andric   if (const auto *CT = T->getAs<VectorType>())
460*700637cbSDimitry Andric     return CT->getElementType();
461*700637cbSDimitry Andric 
462*700637cbSDimitry Andric   return T;
463*700637cbSDimitry Andric }
464*700637cbSDimitry Andric 
getDataType(const ASTContext & Ctx) const465*700637cbSDimitry Andric QualType Descriptor::getDataType(const ASTContext &Ctx) const {
466*700637cbSDimitry Andric   auto MakeArrayType = [&](QualType ElemType) -> QualType {
467*700637cbSDimitry Andric     if (IsArray)
468*700637cbSDimitry Andric       return Ctx.getConstantArrayType(
469*700637cbSDimitry Andric           ElemType, APInt(64, static_cast<uint64_t>(getNumElems()), false),
470*700637cbSDimitry Andric           nullptr, ArraySizeModifier::Normal, 0);
471*700637cbSDimitry Andric     return ElemType;
472*700637cbSDimitry Andric   };
473*700637cbSDimitry Andric 
474*700637cbSDimitry Andric   if (const auto *E = asExpr()) {
475*700637cbSDimitry Andric     if (isa<CXXNewExpr>(E))
476*700637cbSDimitry Andric       return MakeArrayType(E->getType()->getPointeeType());
477*700637cbSDimitry Andric 
478*700637cbSDimitry Andric     // std::allocator.allocate() call.
479*700637cbSDimitry Andric     if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
480*700637cbSDimitry Andric         ME && ME->getRecordDecl()->getName() == "allocator" &&
481*700637cbSDimitry Andric         ME->getMethodDecl()->getName() == "allocate")
482*700637cbSDimitry Andric       return MakeArrayType(E->getType()->getPointeeType());
483*700637cbSDimitry Andric     return E->getType();
484*700637cbSDimitry Andric   }
485*700637cbSDimitry Andric 
486*700637cbSDimitry Andric   return getType();
487*700637cbSDimitry Andric }
488*700637cbSDimitry Andric 
getLocation() const489*700637cbSDimitry Andric SourceLocation Descriptor::getLocation() const {
490*700637cbSDimitry Andric   if (auto *D = dyn_cast<const Decl *>(Source))
491*700637cbSDimitry Andric     return D->getLocation();
492*700637cbSDimitry Andric   if (auto *E = dyn_cast<const Expr *>(Source))
493*700637cbSDimitry Andric     return E->getExprLoc();
494*700637cbSDimitry Andric   llvm_unreachable("Invalid descriptor type");
495*700637cbSDimitry Andric }
496*700637cbSDimitry Andric 
getLoc() const497*700637cbSDimitry Andric SourceInfo Descriptor::getLoc() const {
498*700637cbSDimitry Andric   if (const auto *D = dyn_cast<const Decl *>(Source))
499*700637cbSDimitry Andric     return SourceInfo(D);
500*700637cbSDimitry Andric   if (const auto *E = dyn_cast<const Expr *>(Source))
501*700637cbSDimitry Andric     return SourceInfo(E);
502*700637cbSDimitry Andric   llvm_unreachable("Invalid descriptor type");
503*700637cbSDimitry Andric }
504*700637cbSDimitry Andric 
hasTrivialDtor() const505*700637cbSDimitry Andric bool Descriptor::hasTrivialDtor() const {
506*700637cbSDimitry Andric   if (isPrimitive() || isPrimitiveArray() || isDummy())
507*700637cbSDimitry Andric     return true;
508*700637cbSDimitry Andric 
509*700637cbSDimitry Andric   if (isRecord()) {
510*700637cbSDimitry Andric     assert(ElemRecord);
511*700637cbSDimitry Andric     const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
512*700637cbSDimitry Andric     return !Dtor || Dtor->isTrivial();
513*700637cbSDimitry Andric   }
514*700637cbSDimitry Andric 
515*700637cbSDimitry Andric   // Composite arrays.
516*700637cbSDimitry Andric   assert(ElemDesc);
517*700637cbSDimitry Andric   return ElemDesc->hasTrivialDtor();
518*700637cbSDimitry Andric }
519*700637cbSDimitry Andric 
isUnion() const520*700637cbSDimitry Andric bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
521*700637cbSDimitry Andric 
InitMap(unsigned N)522*700637cbSDimitry Andric InitMap::InitMap(unsigned N)
523*700637cbSDimitry Andric     : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {
524*700637cbSDimitry Andric   std::fill_n(data(), numFields(N), 0);
525*700637cbSDimitry Andric }
526*700637cbSDimitry Andric 
initializeElement(unsigned I)527*700637cbSDimitry Andric bool InitMap::initializeElement(unsigned I) {
528*700637cbSDimitry Andric   unsigned Bucket = I / PER_FIELD;
529*700637cbSDimitry Andric   T Mask = T(1) << (I % PER_FIELD);
530*700637cbSDimitry Andric   if (!(data()[Bucket] & Mask)) {
531*700637cbSDimitry Andric     data()[Bucket] |= Mask;
532*700637cbSDimitry Andric     UninitFields -= 1;
533*700637cbSDimitry Andric   }
534*700637cbSDimitry Andric   return UninitFields == 0;
535*700637cbSDimitry Andric }
536*700637cbSDimitry Andric 
isElementInitialized(unsigned I) const537*700637cbSDimitry Andric bool InitMap::isElementInitialized(unsigned I) const {
538*700637cbSDimitry Andric   unsigned Bucket = I / PER_FIELD;
539*700637cbSDimitry Andric   return data()[Bucket] & (T(1) << (I % PER_FIELD));
540*700637cbSDimitry Andric }
541