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