clang 17.0.0git
Descriptor.cpp
Go to the documentation of this file.
1//===--- Descriptor.cpp - Types for the constexpr VM ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Descriptor.h"
10#include "Boolean.h"
11#include "Floating.h"
12#include "Pointer.h"
13#include "PrimType.h"
14#include "Record.h"
15
16using namespace clang;
17using namespace clang::interp;
18
19template <typename T>
20static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *) {
21 new (Ptr) T();
22}
23
24template <typename T> static void dtorTy(Block *, char *Ptr, Descriptor *) {
25 reinterpret_cast<T *>(Ptr)->~T();
26}
27
28template <typename T>
29static void moveTy(Block *, char *Src, char *Dst, Descriptor *) {
30 auto *SrcPtr = reinterpret_cast<T *>(Src);
31 auto *DstPtr = reinterpret_cast<T *>(Dst);
32 new (DstPtr) T(std::move(*SrcPtr));
33}
34
35template <typename T>
36static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) {
37 for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
38 new (&reinterpret_cast<T *>(Ptr)[I]) T();
39 }
40}
41
42template <typename T>
43static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) {
44 InitMap *IM = *reinterpret_cast<InitMap **>(Ptr);
45 if (IM != (InitMap *)-1)
46 free(IM);
47
48 Ptr += sizeof(InitMap *);
49 for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
50 reinterpret_cast<T *>(Ptr)[I].~T();
51 }
52}
53
54template <typename T>
55static void moveArrayTy(Block *, char *Src, char *Dst, Descriptor *D) {
56 for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
57 auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
58 auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
59 new (DstPtr) T(std::move(*SrcPtr));
60 }
61}
62
63static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable,
64 bool IsActive, Descriptor *D) {
65 const unsigned NumElems = D->getNumElems();
66 const unsigned ElemSize =
68
69 unsigned ElemOffset = 0;
70 for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
71 auto *ElemPtr = Ptr + ElemOffset;
72 auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
73 auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
74 auto *SD = D->ElemDesc;
75
76 Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
77 Desc->Desc = SD;
78 Desc->IsInitialized = true;
79 Desc->IsBase = false;
80 Desc->IsActive = IsActive;
81 Desc->IsConst = IsConst || D->IsConst;
82 Desc->IsFieldMutable = IsMutable || D->IsMutable;
83 if (auto Fn = D->ElemDesc->CtorFn)
84 Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsActive,
85 D->ElemDesc);
86 }
87}
88
89static void dtorArrayDesc(Block *B, char *Ptr, Descriptor *D) {
90 const unsigned NumElems = D->getNumElems();
91 const unsigned ElemSize =
93
94 unsigned ElemOffset = 0;
95 for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
96 auto *ElemPtr = Ptr + ElemOffset;
97 auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
98 auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
99 if (auto Fn = D->ElemDesc->DtorFn)
100 Fn(B, ElemLoc, D->ElemDesc);
101 }
102}
103
104static void moveArrayDesc(Block *B, char *Src, char *Dst, Descriptor *D) {
105 const unsigned NumElems = D->getNumElems();
106 const unsigned ElemSize =
107 D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
108
109 unsigned ElemOffset = 0;
110 for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
111 auto *SrcPtr = Src + ElemOffset;
112 auto *DstPtr = Dst + ElemOffset;
113
114 auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);
115 auto *SrcElemLoc = reinterpret_cast<char *>(SrcDesc + 1);
116 auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
117 auto *DstElemLoc = reinterpret_cast<char *>(DstDesc + 1);
118
119 *DstDesc = *SrcDesc;
120 if (auto Fn = D->ElemDesc->MoveFn)
121 Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
122 }
123}
124
125static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable,
126 bool IsActive, Descriptor *D) {
127 const bool IsUnion = D->ElemRecord->isUnion();
128 auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) {
129 auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
130 Desc->Offset = SubOff;
131 Desc->Desc = F;
132 Desc->IsInitialized = F->IsArray && !IsBase;
133 Desc->IsBase = IsBase;
134 Desc->IsActive = IsActive && !IsUnion;
135 Desc->IsConst = IsConst || F->IsConst;
136 Desc->IsFieldMutable = IsMutable || F->IsMutable;
137 if (auto Fn = F->CtorFn)
138 Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsFieldMutable, Desc->IsActive,
139 F);
140 };
141 for (const auto &B : D->ElemRecord->bases())
142 CtorSub(B.Offset, B.Desc, /*isBase=*/true);
143 for (const auto &F : D->ElemRecord->fields())
144 CtorSub(F.Offset, F.Desc, /*isBase=*/false);
145 for (const auto &V : D->ElemRecord->virtual_bases())
146 CtorSub(V.Offset, V.Desc, /*isBase=*/true);
147}
148
149static void dtorRecord(Block *B, char *Ptr, Descriptor *D) {
150 auto DtorSub = [=](unsigned SubOff, Descriptor *F) {
151 if (auto Fn = F->DtorFn)
152 Fn(B, Ptr + SubOff, F);
153 };
154 for (const auto &F : D->ElemRecord->bases())
155 DtorSub(F.Offset, F.Desc);
156 for (const auto &F : D->ElemRecord->fields())
157 DtorSub(F.Offset, F.Desc);
158 for (const auto &F : D->ElemRecord->virtual_bases())
159 DtorSub(F.Offset, F.Desc);
160}
161
162static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D) {
163 for (const auto &F : D->ElemRecord->fields()) {
164 auto FieldOff = F.Offset;
165 auto FieldDesc = F.Desc;
166
167 *(reinterpret_cast<Descriptor **>(Dst + FieldOff) - 1) = FieldDesc;
168 if (auto Fn = FieldDesc->MoveFn)
169 Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc);
170 }
171}
172
174 // Floating types are special. They are primitives, but need their
175 // constructor called.
176 if (Type == PT_Float)
177 return ctorTy<PrimConv<PT_Float>::T>;
178
179 COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
180}
181
183 COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
184}
185
187 COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
188}
189
191 COMPOSITE_TYPE_SWITCH(Type, return ctorArrayTy<T>, return nullptr);
192}
193
195 TYPE_SWITCH(Type, return dtorArrayTy<T>);
196 llvm_unreachable("unknown Expr");
197}
198
200 COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr);
201}
202
204 bool IsConst, bool IsTemporary, bool IsMutable)
205 : Source(D), ElemSize(primSize(Type)), Size(ElemSize),
206 MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), IsConst(IsConst),
207 IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(getCtorPrim(Type)),
208 DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {
209 assert(AllocSize >= Size);
210 assert(Source && "Missing source");
211}
212
214 size_t NumElems, bool IsConst, bool IsTemporary,
215 bool IsMutable)
216 : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
217 MDSize(MD.value_or(0)),
218 AllocSize(align(Size) + sizeof(InitMap *) + MDSize), IsConst(IsConst),
219 IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
220 CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
221 MoveFn(getMoveArrayPrim(Type)) {
222 assert(Source && "Missing source");
223}
224
225Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
227 : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), MDSize(0),
228 AllocSize(alignof(void *)), IsConst(true), IsMutable(false),
229 IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)),
230 DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
231 assert(Source && "Missing source");
232}
233
235 unsigned NumElems, bool IsConst, bool IsTemporary,
236 bool IsMutable)
237 : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
238 Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
239 AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
240 ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
241 IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
242 DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
243 assert(Source && "Missing source");
244}
245
246Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
248 : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
249 Size(UnknownSizeMark), MDSize(0), AllocSize(alignof(void *)),
250 ElemDesc(Elem), IsConst(true), IsMutable(false), IsTemporary(IsTemporary),
251 IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc),
252 MoveFn(moveArrayDesc) {
253 assert(Source && "Missing source");
254}
255
257 bool IsConst, bool IsTemporary, bool IsMutable)
258 : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
259 Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
260 ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
261 IsTemporary(IsTemporary), CtorFn(ctorRecord), DtorFn(dtorRecord),
262 MoveFn(moveRecord) {
263 assert(Source && "Missing source");
264}
265
267 if (auto *E = asExpr())
268 return E->getType();
269 if (auto *D = asValueDecl())
270 return D->getType();
271 llvm_unreachable("Invalid descriptor type");
272}
273
275 if (auto *D = Source.dyn_cast<const Decl *>())
276 return D->getLocation();
277 if (auto *E = Source.dyn_cast<const Expr *>())
278 return E->getExprLoc();
279 llvm_unreachable("Invalid descriptor type");
280}
281
282InitMap::InitMap(unsigned N) : UninitFields(N) {
283 std::fill_n(data(), (N + PER_FIELD - 1) / PER_FIELD, 0);
284}
285
286InitMap::T *InitMap::data() {
287 auto *Start = reinterpret_cast<char *>(this) + align(sizeof(InitMap));
288 return reinterpret_cast<T *>(Start);
289}
290
291const InitMap::T *InitMap::data() const {
292 auto *Start = reinterpret_cast<const char *>(this) + align(sizeof(InitMap));
293 return reinterpret_cast<const T *>(Start);
294}
295
296bool InitMap::initialize(unsigned I) {
297 unsigned Bucket = I / PER_FIELD;
298 T Mask = T(1) << (I % PER_FIELD);
299 if (!(data()[Bucket] & Mask)) {
300 data()[Bucket] |= Mask;
301 UninitFields -= 1;
302 }
303 return UninitFields == 0;
304}
305
306bool InitMap::isInitialized(unsigned I) const {
307 unsigned Bucket = I / PER_FIELD;
308 return data()[Bucket] & (T(1) << (I % PER_FIELD));
309}
310
312 const size_t NumFields = ((N + PER_FIELD - 1) / PER_FIELD);
313 const size_t Size = align(sizeof(InitMap)) + NumFields * PER_FIELD;
314 return new (malloc(Size)) InitMap(N);
315}
#define V(N, I)
Definition: ASTContext.h:3216
static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D)
Definition: Descriptor.cpp:36
static BlockCtorFn getCtorArrayPrim(PrimType Type)
Definition: Descriptor.cpp:190
static BlockMoveFn getMoveArrayPrim(PrimType Type)
Definition: Descriptor.cpp:199
static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *)
Definition: Descriptor.cpp:20
static BlockMoveFn getMovePrim(PrimType Type)
Definition: Descriptor.cpp:186
static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable, bool IsActive, Descriptor *D)
Definition: Descriptor.cpp:63
static void moveTy(Block *, char *Src, char *Dst, Descriptor *)
Definition: Descriptor.cpp:29
static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D)
Definition: Descriptor.cpp:162
static void dtorRecord(Block *B, char *Ptr, Descriptor *D)
Definition: Descriptor.cpp:149
static void dtorTy(Block *, char *Ptr, Descriptor *)
Definition: Descriptor.cpp:24
static BlockDtorFn getDtorPrim(PrimType Type)
Definition: Descriptor.cpp:182
static BlockCtorFn getCtorPrim(PrimType Type)
Definition: Descriptor.cpp:173
static BlockDtorFn getDtorArrayPrim(PrimType Type)
Definition: Descriptor.cpp:194
static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable, bool IsActive, Descriptor *D)
Definition: Descriptor.cpp:125
static void moveArrayTy(Block *, char *Src, char *Dst, Descriptor *D)
Definition: Descriptor.cpp:55
static void dtorArrayDesc(Block *B, char *Ptr, Descriptor *D)
Definition: Descriptor.cpp:89
static void moveArrayDesc(Block *B, char *Src, char *Dst, Descriptor *D)
Definition: Descriptor.cpp:104
static void dtorArrayTy(Block *, char *Ptr, Descriptor *D)
Definition: Descriptor.cpp:43
#define COMPOSITE_TYPE_SWITCH(Expr, B, D)
Definition: PrimType.h:95
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:79
__DEVICE__ int max(int __a, int __b)
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
This represents one expression.
Definition: Expr.h:110
A (possibly-)qualified type.
Definition: Type.h:736
Encodes a location in the source.
The base class of the type hierarchy.
Definition: Type.h:1566
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
Descriptor * Desc
Pointer to the stack slot descriptor.
Definition: InterpBlock.h:140
Structure/Class descriptor.
Definition: Record.h:25
bool isUnion() const
Checks if the record is a union.
Definition: Record.h:55
llvm::iterator_range< const_virtual_iter > virtual_bases() const
Definition: Record.h:91
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:83
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:74
void(*)(Block *Storage, char *FieldPtr, bool IsConst, bool IsMutable, bool IsActive, Descriptor *FieldDesc) BlockCtorFn
Invoked whenever a block is created.
Definition: Descriptor.h:33
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:614
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:61
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:29
void(*)(Block *Storage, char *SrcFieldPtr, char *DstFieldPtr, Descriptor *FieldDesc) BlockMoveFn
Invoked when a block with pointers referencing it goes out of scope.
Definition: Descriptor.h:45
void(*)(Block *Storage, char *FieldPtr, Descriptor *FieldDesc) BlockDtorFn
Invoked when a block is destroyed.
Definition: Descriptor.h:38
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:20
llvm::PointerUnion< const Decl *, const Expr * > DeclTy
Definition: Descriptor.h:26
Definition: Format.h:4608
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
#define alignof
Definition: stdalign.h:15
#define true
Definition: stdbool.h:21
#define false
Definition: stdbool.h:22
Token to denote structures of unknown size.
Definition: Descriptor.h:94
Describes a memory block created by an allocation site.
Definition: Descriptor.h:76
const bool IsConst
Flag indicating if the block is mutable.
Definition: Descriptor.h:104
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition: Descriptor.h:164
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:171
const BlockMoveFn MoveFn
Definition: Descriptor.h:115
const BlockDtorFn DtorFn
Definition: Descriptor.h:114
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:145
const BlockCtorFn CtorFn
Storage management methods.
Definition: Descriptor.h:113
QualType getType() const
Definition: Descriptor.cpp:266
SourceLocation getLocation() const
Definition: Descriptor.cpp:274
const bool IsMutable
Flag indicating if a field is mutable.
Definition: Descriptor.h:106
std::optional< unsigned > MetadataSize
Definition: Descriptor.h:96
Descriptor *const ElemDesc
Descriptor of the array element.
Definition: Descriptor.h:102
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable)
Allocates a descriptor for a primitive.
Definition: Descriptor.cpp:203
const Expr * asExpr() const
Definition: Descriptor.h:143
Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:100
Bitfield tracking the initialisation status of elements of primitive arrays.
Definition: Descriptor.h:193
static InitMap * allocate(unsigned N)
Allocates a map holding N elements.
Definition: Descriptor.cpp:311
bool isInitialized(unsigned I) const
Checks if an element was initialized.
Definition: Descriptor.cpp:306
bool initialize(unsigned I)
Initializes an element. Returns true when object if fully initialized.
Definition: Descriptor.cpp:296
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:53
unsigned Offset
Offset inside the structure/array.
Definition: Descriptor.h:55