xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp (revision a7dea1671b87c07d2d266f836bfa8b58efc7c134)
1*a7dea167SDimitry Andric //===--- Descriptor.cpp - Types for the constexpr VM ------------*- C++ -*-===//
2*a7dea167SDimitry Andric //
3*a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*a7dea167SDimitry Andric //
7*a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8*a7dea167SDimitry Andric 
9*a7dea167SDimitry Andric #include "Descriptor.h"
10*a7dea167SDimitry Andric #include "Pointer.h"
11*a7dea167SDimitry Andric #include "PrimType.h"
12*a7dea167SDimitry Andric #include "Record.h"
13*a7dea167SDimitry Andric 
14*a7dea167SDimitry Andric using namespace clang;
15*a7dea167SDimitry Andric using namespace clang::interp;
16*a7dea167SDimitry Andric 
17*a7dea167SDimitry Andric template <typename T>
18*a7dea167SDimitry Andric static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *) {
19*a7dea167SDimitry Andric   new (Ptr) T();
20*a7dea167SDimitry Andric }
21*a7dea167SDimitry Andric 
22*a7dea167SDimitry Andric template <typename T> static void dtorTy(Block *, char *Ptr, Descriptor *) {
23*a7dea167SDimitry Andric   reinterpret_cast<T *>(Ptr)->~T();
24*a7dea167SDimitry Andric }
25*a7dea167SDimitry Andric 
26*a7dea167SDimitry Andric template <typename T>
27*a7dea167SDimitry Andric static void moveTy(Block *, char *Src, char *Dst, Descriptor *) {
28*a7dea167SDimitry Andric   auto *SrcPtr = reinterpret_cast<T *>(Src);
29*a7dea167SDimitry Andric   auto *DstPtr = reinterpret_cast<T *>(Dst);
30*a7dea167SDimitry Andric   new (DstPtr) T(std::move(*SrcPtr));
31*a7dea167SDimitry Andric }
32*a7dea167SDimitry Andric 
33*a7dea167SDimitry Andric template <typename T>
34*a7dea167SDimitry Andric static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) {
35*a7dea167SDimitry Andric   for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
36*a7dea167SDimitry Andric     new (&reinterpret_cast<T *>(Ptr)[I]) T();
37*a7dea167SDimitry Andric   }
38*a7dea167SDimitry Andric }
39*a7dea167SDimitry Andric 
40*a7dea167SDimitry Andric template <typename T>
41*a7dea167SDimitry Andric static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) {
42*a7dea167SDimitry Andric   for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
43*a7dea167SDimitry Andric     reinterpret_cast<T *>(Ptr)[I].~T();
44*a7dea167SDimitry Andric   }
45*a7dea167SDimitry Andric }
46*a7dea167SDimitry Andric 
47*a7dea167SDimitry Andric template <typename T>
48*a7dea167SDimitry Andric static void moveArrayTy(Block *, char *Src, char *Dst, Descriptor *D) {
49*a7dea167SDimitry Andric   for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
50*a7dea167SDimitry Andric     auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
51*a7dea167SDimitry Andric     auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
52*a7dea167SDimitry Andric     new (DstPtr) T(std::move(*SrcPtr));
53*a7dea167SDimitry Andric   }
54*a7dea167SDimitry Andric }
55*a7dea167SDimitry Andric 
56*a7dea167SDimitry Andric static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable,
57*a7dea167SDimitry Andric                           bool IsActive, Descriptor *D) {
58*a7dea167SDimitry Andric   const unsigned NumElems = D->getNumElems();
59*a7dea167SDimitry Andric   const unsigned ElemSize =
60*a7dea167SDimitry Andric       D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
61*a7dea167SDimitry Andric 
62*a7dea167SDimitry Andric   unsigned ElemOffset = 0;
63*a7dea167SDimitry Andric   for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
64*a7dea167SDimitry Andric     auto *ElemPtr = Ptr + ElemOffset;
65*a7dea167SDimitry Andric     auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
66*a7dea167SDimitry Andric     auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
67*a7dea167SDimitry Andric     auto *SD = D->ElemDesc;
68*a7dea167SDimitry Andric 
69*a7dea167SDimitry Andric     Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
70*a7dea167SDimitry Andric     Desc->Desc = SD;
71*a7dea167SDimitry Andric     Desc->IsInitialized = true;
72*a7dea167SDimitry Andric     Desc->IsBase = false;
73*a7dea167SDimitry Andric     Desc->IsActive = IsActive;
74*a7dea167SDimitry Andric     Desc->IsConst = IsConst || D->IsConst;
75*a7dea167SDimitry Andric     Desc->IsMutable = IsMutable || D->IsMutable;
76*a7dea167SDimitry Andric     if (auto Fn = D->ElemDesc->CtorFn)
77*a7dea167SDimitry Andric       Fn(B, ElemLoc, Desc->IsConst, Desc->IsMutable, IsActive, D->ElemDesc);
78*a7dea167SDimitry Andric   }
79*a7dea167SDimitry Andric }
80*a7dea167SDimitry Andric 
81*a7dea167SDimitry Andric static void dtorArrayDesc(Block *B, char *Ptr, Descriptor *D) {
82*a7dea167SDimitry Andric   const unsigned NumElems = D->getNumElems();
83*a7dea167SDimitry Andric   const unsigned ElemSize =
84*a7dea167SDimitry Andric       D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
85*a7dea167SDimitry Andric 
86*a7dea167SDimitry Andric   unsigned ElemOffset = 0;
87*a7dea167SDimitry Andric   for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
88*a7dea167SDimitry Andric     auto *ElemPtr = Ptr + ElemOffset;
89*a7dea167SDimitry Andric     auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
90*a7dea167SDimitry Andric     auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
91*a7dea167SDimitry Andric     if (auto Fn = D->ElemDesc->DtorFn)
92*a7dea167SDimitry Andric       Fn(B, ElemLoc, D->ElemDesc);
93*a7dea167SDimitry Andric   }
94*a7dea167SDimitry Andric }
95*a7dea167SDimitry Andric 
96*a7dea167SDimitry Andric static void moveArrayDesc(Block *B, char *Src, char *Dst, Descriptor *D) {
97*a7dea167SDimitry Andric   const unsigned NumElems = D->getNumElems();
98*a7dea167SDimitry Andric   const unsigned ElemSize =
99*a7dea167SDimitry Andric       D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
100*a7dea167SDimitry Andric 
101*a7dea167SDimitry Andric   unsigned ElemOffset = 0;
102*a7dea167SDimitry Andric   for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
103*a7dea167SDimitry Andric     auto *SrcPtr = Src + ElemOffset;
104*a7dea167SDimitry Andric     auto *DstPtr = Dst + ElemOffset;
105*a7dea167SDimitry Andric 
106*a7dea167SDimitry Andric     auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);
107*a7dea167SDimitry Andric     auto *SrcElemLoc = reinterpret_cast<char *>(SrcDesc + 1);
108*a7dea167SDimitry Andric     auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
109*a7dea167SDimitry Andric     auto *DstElemLoc = reinterpret_cast<char *>(DstDesc + 1);
110*a7dea167SDimitry Andric 
111*a7dea167SDimitry Andric     *DstDesc = *SrcDesc;
112*a7dea167SDimitry Andric     if (auto Fn = D->ElemDesc->MoveFn)
113*a7dea167SDimitry Andric       Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
114*a7dea167SDimitry Andric   }
115*a7dea167SDimitry Andric }
116*a7dea167SDimitry Andric 
117*a7dea167SDimitry Andric static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable,
118*a7dea167SDimitry Andric                        bool IsActive, Descriptor *D) {
119*a7dea167SDimitry Andric   const bool IsUnion = D->ElemRecord->isUnion();
120*a7dea167SDimitry Andric   auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) {
121*a7dea167SDimitry Andric     auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
122*a7dea167SDimitry Andric     Desc->Offset = SubOff;
123*a7dea167SDimitry Andric     Desc->Desc = F;
124*a7dea167SDimitry Andric     Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase;
125*a7dea167SDimitry Andric     Desc->IsBase = IsBase;
126*a7dea167SDimitry Andric     Desc->IsActive = IsActive && !IsUnion;
127*a7dea167SDimitry Andric     Desc->IsConst = IsConst || F->IsConst;
128*a7dea167SDimitry Andric     Desc->IsMutable = IsMutable || F->IsMutable;
129*a7dea167SDimitry Andric     if (auto Fn = F->CtorFn)
130*a7dea167SDimitry Andric       Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsMutable, Desc->IsActive, F);
131*a7dea167SDimitry Andric   };
132*a7dea167SDimitry Andric   for (const auto &B : D->ElemRecord->bases())
133*a7dea167SDimitry Andric     CtorSub(B.Offset, B.Desc, /*isBase=*/true);
134*a7dea167SDimitry Andric   for (const auto &F : D->ElemRecord->fields())
135*a7dea167SDimitry Andric     CtorSub(F.Offset, F.Desc, /*isBase=*/false);
136*a7dea167SDimitry Andric   for (const auto &V : D->ElemRecord->virtual_bases())
137*a7dea167SDimitry Andric     CtorSub(V.Offset, V.Desc, /*isBase=*/true);
138*a7dea167SDimitry Andric }
139*a7dea167SDimitry Andric 
140*a7dea167SDimitry Andric static void dtorRecord(Block *B, char *Ptr, Descriptor *D) {
141*a7dea167SDimitry Andric   auto DtorSub = [=](unsigned SubOff, Descriptor *F) {
142*a7dea167SDimitry Andric     if (auto Fn = F->DtorFn)
143*a7dea167SDimitry Andric       Fn(B, Ptr + SubOff, F);
144*a7dea167SDimitry Andric   };
145*a7dea167SDimitry Andric   for (const auto &F : D->ElemRecord->bases())
146*a7dea167SDimitry Andric     DtorSub(F.Offset, F.Desc);
147*a7dea167SDimitry Andric   for (const auto &F : D->ElemRecord->fields())
148*a7dea167SDimitry Andric     DtorSub(F.Offset, F.Desc);
149*a7dea167SDimitry Andric   for (const auto &F : D->ElemRecord->virtual_bases())
150*a7dea167SDimitry Andric     DtorSub(F.Offset, F.Desc);
151*a7dea167SDimitry Andric }
152*a7dea167SDimitry Andric 
153*a7dea167SDimitry Andric static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D) {
154*a7dea167SDimitry Andric   for (const auto &F : D->ElemRecord->fields()) {
155*a7dea167SDimitry Andric     auto FieldOff = F.Offset;
156*a7dea167SDimitry Andric     auto FieldDesc = F.Desc;
157*a7dea167SDimitry Andric 
158*a7dea167SDimitry Andric     *(reinterpret_cast<Descriptor **>(Dst + FieldOff) - 1) = FieldDesc;
159*a7dea167SDimitry Andric     if (auto Fn = FieldDesc->MoveFn)
160*a7dea167SDimitry Andric       Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc);
161*a7dea167SDimitry Andric   }
162*a7dea167SDimitry Andric }
163*a7dea167SDimitry Andric 
164*a7dea167SDimitry Andric static BlockCtorFn getCtorPrim(PrimType Type) {
165*a7dea167SDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
166*a7dea167SDimitry Andric }
167*a7dea167SDimitry Andric 
168*a7dea167SDimitry Andric static BlockDtorFn getDtorPrim(PrimType Type) {
169*a7dea167SDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
170*a7dea167SDimitry Andric }
171*a7dea167SDimitry Andric 
172*a7dea167SDimitry Andric static BlockMoveFn getMovePrim(PrimType Type) {
173*a7dea167SDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
174*a7dea167SDimitry Andric }
175*a7dea167SDimitry Andric 
176*a7dea167SDimitry Andric static BlockCtorFn getCtorArrayPrim(PrimType Type) {
177*a7dea167SDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return ctorArrayTy<T>, return nullptr);
178*a7dea167SDimitry Andric }
179*a7dea167SDimitry Andric 
180*a7dea167SDimitry Andric static BlockDtorFn getDtorArrayPrim(PrimType Type) {
181*a7dea167SDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr);
182*a7dea167SDimitry Andric }
183*a7dea167SDimitry Andric 
184*a7dea167SDimitry Andric static BlockMoveFn getMoveArrayPrim(PrimType Type) {
185*a7dea167SDimitry Andric   COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr);
186*a7dea167SDimitry Andric }
187*a7dea167SDimitry Andric 
188*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsConst,
189*a7dea167SDimitry Andric                        bool IsTemporary, bool IsMutable)
190*a7dea167SDimitry Andric     : Source(D), ElemSize(primSize(Type)), Size(ElemSize), AllocSize(Size),
191*a7dea167SDimitry Andric       IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
192*a7dea167SDimitry Andric       CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),
193*a7dea167SDimitry Andric       MoveFn(getMovePrim(Type)) {
194*a7dea167SDimitry Andric   assert(Source && "Missing source");
195*a7dea167SDimitry Andric }
196*a7dea167SDimitry Andric 
197*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems,
198*a7dea167SDimitry Andric                        bool IsConst, bool IsTemporary, bool IsMutable)
199*a7dea167SDimitry Andric     : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
200*a7dea167SDimitry Andric       AllocSize(align(Size) + sizeof(InitMap *)), IsConst(IsConst),
201*a7dea167SDimitry Andric       IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
202*a7dea167SDimitry Andric       CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
203*a7dea167SDimitry Andric       MoveFn(getMoveArrayPrim(Type)) {
204*a7dea167SDimitry Andric   assert(Source && "Missing source");
205*a7dea167SDimitry Andric }
206*a7dea167SDimitry Andric 
207*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
208*a7dea167SDimitry Andric                        UnknownSize)
209*a7dea167SDimitry Andric     : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
210*a7dea167SDimitry Andric       AllocSize(alignof(void *)), IsConst(true), IsMutable(false),
211*a7dea167SDimitry Andric       IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)),
212*a7dea167SDimitry Andric       DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
213*a7dea167SDimitry Andric   assert(Source && "Missing source");
214*a7dea167SDimitry Andric }
215*a7dea167SDimitry Andric 
216*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems,
217*a7dea167SDimitry Andric                        bool IsConst, bool IsTemporary, bool IsMutable)
218*a7dea167SDimitry Andric     : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
219*a7dea167SDimitry Andric       Size(ElemSize * NumElems),
220*a7dea167SDimitry Andric       AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem),
221*a7dea167SDimitry Andric       IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
222*a7dea167SDimitry Andric       IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc),
223*a7dea167SDimitry Andric       MoveFn(moveArrayDesc) {
224*a7dea167SDimitry Andric   assert(Source && "Missing source");
225*a7dea167SDimitry Andric }
226*a7dea167SDimitry Andric 
227*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
228*a7dea167SDimitry Andric                        UnknownSize)
229*a7dea167SDimitry Andric     : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
230*a7dea167SDimitry Andric       Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem),
231*a7dea167SDimitry Andric       IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
232*a7dea167SDimitry Andric       CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
233*a7dea167SDimitry Andric   assert(Source && "Missing source");
234*a7dea167SDimitry Andric }
235*a7dea167SDimitry Andric 
236*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, Record *R, bool IsConst,
237*a7dea167SDimitry Andric                        bool IsTemporary, bool IsMutable)
238*a7dea167SDimitry Andric     : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
239*a7dea167SDimitry Andric       Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst),
240*a7dea167SDimitry Andric       IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(ctorRecord),
241*a7dea167SDimitry Andric       DtorFn(dtorRecord), MoveFn(moveRecord) {
242*a7dea167SDimitry Andric   assert(Source && "Missing source");
243*a7dea167SDimitry Andric }
244*a7dea167SDimitry Andric 
245*a7dea167SDimitry Andric QualType Descriptor::getType() const {
246*a7dea167SDimitry Andric   if (auto *E = asExpr())
247*a7dea167SDimitry Andric     return E->getType();
248*a7dea167SDimitry Andric   if (auto *D = asValueDecl())
249*a7dea167SDimitry Andric     return D->getType();
250*a7dea167SDimitry Andric   llvm_unreachable("Invalid descriptor type");
251*a7dea167SDimitry Andric }
252*a7dea167SDimitry Andric 
253*a7dea167SDimitry Andric SourceLocation Descriptor::getLocation() const {
254*a7dea167SDimitry Andric   if (auto *D = Source.dyn_cast<const Decl *>())
255*a7dea167SDimitry Andric     return D->getLocation();
256*a7dea167SDimitry Andric   if (auto *E = Source.dyn_cast<const Expr *>())
257*a7dea167SDimitry Andric     return E->getExprLoc();
258*a7dea167SDimitry Andric   llvm_unreachable("Invalid descriptor type");
259*a7dea167SDimitry Andric }
260*a7dea167SDimitry Andric 
261*a7dea167SDimitry Andric InitMap::InitMap(unsigned N) : UninitFields(N) {
262*a7dea167SDimitry Andric   for (unsigned I = 0; I < N / PER_FIELD; ++I) {
263*a7dea167SDimitry Andric     data()[I] = 0;
264*a7dea167SDimitry Andric   }
265*a7dea167SDimitry Andric }
266*a7dea167SDimitry Andric 
267*a7dea167SDimitry Andric InitMap::T *InitMap::data() {
268*a7dea167SDimitry Andric   auto *Start = reinterpret_cast<char *>(this) + align(sizeof(InitMap));
269*a7dea167SDimitry Andric   return reinterpret_cast<T *>(Start);
270*a7dea167SDimitry Andric }
271*a7dea167SDimitry Andric 
272*a7dea167SDimitry Andric bool InitMap::initialize(unsigned I) {
273*a7dea167SDimitry Andric   unsigned Bucket = I / PER_FIELD;
274*a7dea167SDimitry Andric   unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
275*a7dea167SDimitry Andric   if (!(data()[Bucket] & Mask)) {
276*a7dea167SDimitry Andric     data()[Bucket] |= Mask;
277*a7dea167SDimitry Andric     UninitFields -= 1;
278*a7dea167SDimitry Andric   }
279*a7dea167SDimitry Andric   return UninitFields == 0;
280*a7dea167SDimitry Andric }
281*a7dea167SDimitry Andric 
282*a7dea167SDimitry Andric bool InitMap::isInitialized(unsigned I) {
283*a7dea167SDimitry Andric   unsigned Bucket = I / PER_FIELD;
284*a7dea167SDimitry Andric   unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
285*a7dea167SDimitry Andric   return data()[Bucket] & Mask;
286*a7dea167SDimitry Andric }
287*a7dea167SDimitry Andric 
288*a7dea167SDimitry Andric InitMap *InitMap::allocate(unsigned N) {
289*a7dea167SDimitry Andric   const size_t NumFields = ((N + PER_FIELD - 1) / PER_FIELD);
290*a7dea167SDimitry Andric   const size_t Size = align(sizeof(InitMap)) + NumFields * PER_FIELD;
291*a7dea167SDimitry Andric   return new (malloc(Size)) InitMap(N);
292*a7dea167SDimitry Andric }
293