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