clang  19.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 "FunctionPointer.h"
13 #include "IntegralAP.h"
14 #include "Pointer.h"
15 #include "PrimType.h"
16 #include "Record.h"
17 
18 using namespace clang;
19 using namespace clang::interp;
20 
21 template <typename T>
22 static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool,
23  const Descriptor *) {
24  new (Ptr) T();
25 }
26 
27 template <typename T>
28 static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
29  reinterpret_cast<T *>(Ptr)->~T();
30 }
31 
32 template <typename T>
33 static void moveTy(Block *, const std::byte *Src, std::byte *Dst,
34  const Descriptor *) {
35  const auto *SrcPtr = reinterpret_cast<const T *>(Src);
36  auto *DstPtr = reinterpret_cast<T *>(Dst);
37  new (DstPtr) T(std::move(*SrcPtr));
38 }
39 
40 template <typename T>
41 static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool,
42  const Descriptor *D) {
43  new (Ptr) InitMapPtr(std::nullopt);
44 
45  Ptr += sizeof(InitMapPtr);
46  for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
47  new (&reinterpret_cast<T *>(Ptr)[I]) T();
48  }
49 }
50 
51 template <typename T>
52 static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
53  InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
54 
55  if (IMP)
56  IMP = std::nullopt;
57  Ptr += sizeof(InitMapPtr);
58  for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
59  reinterpret_cast<T *>(Ptr)[I].~T();
60  }
61 }
62 
63 template <typename T>
64 static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst,
65  const Descriptor *D) {
66  // FIXME: Need to copy the InitMap?
67  Src += sizeof(InitMapPtr);
68  Dst += sizeof(InitMapPtr);
69  for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
70  const auto *SrcPtr = &reinterpret_cast<const T *>(Src)[I];
71  auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
72  new (DstPtr) T(std::move(*SrcPtr));
73  }
74 }
75 
76 static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
77  bool IsMutable, bool IsActive, const Descriptor *D) {
78  const unsigned NumElems = D->getNumElems();
79  const unsigned ElemSize =
80  D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
81 
82  unsigned ElemOffset = 0;
83  for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
84  auto *ElemPtr = Ptr + ElemOffset;
85  auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
86  auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
87  auto *SD = D->ElemDesc;
88 
89  Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
90  Desc->Desc = SD;
91  Desc->IsInitialized = true;
92  Desc->IsBase = false;
93  Desc->IsActive = IsActive;
94  Desc->IsConst = IsConst || D->IsConst;
95  Desc->IsFieldMutable = IsMutable || D->IsMutable;
96  if (auto Fn = D->ElemDesc->CtorFn)
97  Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsActive,
98  D->ElemDesc);
99  }
100 }
101 
102 static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
103  const unsigned NumElems = D->getNumElems();
104  const unsigned ElemSize =
105  D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
106 
107  unsigned ElemOffset = 0;
108  for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
109  auto *ElemPtr = Ptr + ElemOffset;
110  auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
111  auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
112  if (auto Fn = D->ElemDesc->DtorFn)
113  Fn(B, ElemLoc, D->ElemDesc);
114  }
115 }
116 
117 static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst,
118  const Descriptor *D) {
119  const unsigned NumElems = D->getNumElems();
120  const unsigned ElemSize =
121  D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
122 
123  unsigned ElemOffset = 0;
124  for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
125  const auto *SrcPtr = Src + ElemOffset;
126  auto *DstPtr = Dst + ElemOffset;
127 
128  const auto *SrcDesc = reinterpret_cast<const InlineDescriptor *>(SrcPtr);
129  const auto *SrcElemLoc = reinterpret_cast<const std::byte *>(SrcDesc + 1);
130  auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
131  auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1);
132 
133  *DstDesc = *SrcDesc;
134  if (auto Fn = D->ElemDesc->MoveFn)
135  Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
136  }
137 }
138 
139 static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
140  bool IsActive, bool IsUnion, const Descriptor *D,
141  unsigned FieldOffset) {
142  auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
143  Desc->Offset = FieldOffset;
144  Desc->Desc = D;
145  Desc->IsInitialized = D->IsArray;
146  Desc->IsBase = false;
147  Desc->IsActive = IsActive && !IsUnion;
148  Desc->IsConst = IsConst || D->IsConst;
149  Desc->IsFieldMutable = IsMutable || D->IsMutable;
150 
151  if (auto Fn = D->CtorFn)
152  Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
153  Desc->IsActive, D);
154 }
155 
156 static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
157  bool IsActive, const Descriptor *D, unsigned FieldOffset,
158  bool IsVirtualBase) {
159  assert(D);
160  assert(D->ElemRecord);
161 
162  bool IsUnion = D->ElemRecord->isUnion();
163  auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
164  Desc->Offset = FieldOffset;
165  Desc->Desc = D;
166  Desc->IsInitialized = D->IsArray;
167  Desc->IsBase = true;
168  Desc->IsActive = IsActive && !IsUnion;
169  Desc->IsConst = IsConst || D->IsConst;
170  Desc->IsFieldMutable = IsMutable || D->IsMutable;
171 
172  for (const auto &V : D->ElemRecord->bases())
173  initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,
174  V.Offset, false);
175  for (const auto &F : D->ElemRecord->fields())
176  initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion, F.Desc,
177  F.Offset);
178 
179  // If this is initializing a virtual base, we do NOT want to consider its
180  // virtual bases, those are already flattened into the parent record when
181  // creating it.
182  if (IsVirtualBase)
183  return;
184 
185  for (const auto &V : D->ElemRecord->virtual_bases())
186  initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,
187  V.Offset, true);
188 }
189 
190 static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
191  bool IsActive, const Descriptor *D) {
192  for (const auto &V : D->ElemRecord->bases())
193  initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false);
194  for (const auto &F : D->ElemRecord->fields())
195  initField(B, Ptr, IsConst, IsMutable, IsActive, D->ElemRecord->isUnion(), F.Desc, F.Offset);
196  for (const auto &V : D->ElemRecord->virtual_bases())
197  initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true);
198 }
199 
200 static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
201  auto DtorSub = [=](unsigned SubOff, const Descriptor *F) {
202  if (auto Fn = F->DtorFn)
203  Fn(B, Ptr + SubOff, F);
204  };
205  for (const auto &F : D->ElemRecord->bases())
206  DtorSub(F.Offset, F.Desc);
207  for (const auto &F : D->ElemRecord->fields())
208  DtorSub(F.Offset, F.Desc);
209  for (const auto &F : D->ElemRecord->virtual_bases())
210  DtorSub(F.Offset, F.Desc);
211 }
212 
213 static void moveRecord(Block *B, const std::byte *Src, std::byte *Dst,
214  const Descriptor *D) {
215  for (const auto &F : D->ElemRecord->fields()) {
216  auto FieldOff = F.Offset;
217  auto *FieldDesc = F.Desc;
218 
219  if (auto Fn = FieldDesc->MoveFn)
220  Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc);
221  }
222 }
223 
225  // Floating types are special. They are primitives, but need their
226  // constructor called.
227  if (Type == PT_Float)
229  if (Type == PT_IntAP)
231  if (Type == PT_IntAPS)
233 
234  COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
235 }
236 
238  // Floating types are special. They are primitives, but need their
239  // destructor called, since they might allocate memory.
240  if (Type == PT_Float)
242  if (Type == PT_IntAP)
244  if (Type == PT_IntAPS)
246 
247  COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
248 }
249 
251  COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
252 }
253 
255  TYPE_SWITCH(Type, return ctorArrayTy<T>);
256  llvm_unreachable("unknown Expr");
257 }
258 
260  TYPE_SWITCH(Type, return dtorArrayTy<T>);
261  llvm_unreachable("unknown Expr");
262 }
263 
265  TYPE_SWITCH(Type, return moveArrayTy<T>);
266  llvm_unreachable("unknown Expr");
267 }
268 
269 /// Primitives.
271  bool IsConst, bool IsTemporary, bool IsMutable)
272  : Source(D), ElemSize(primSize(Type)), Size(ElemSize),
273  MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),
274  IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
275  CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),
276  MoveFn(getMovePrim(Type)) {
277  assert(AllocSize >= Size);
278  assert(Source && "Missing source");
279 }
280 
281 /// Primitive arrays.
283  size_t NumElems, bool IsConst, bool IsTemporary,
284  bool IsMutable)
285  : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
286  MDSize(MD.value_or(0)),
287  AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),
288  IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
289  IsArray(true), CtorFn(getCtorArrayPrim(Type)),
290  DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
291  assert(Source && "Missing source");
292 }
293 
294 /// Primitive unknown-size arrays.
296  bool IsTemporary, UnknownSize)
297  : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
298  MDSize(MD.value_or(0)),
299  AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), IsConst(true),
300  IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
301  CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
302  MoveFn(getMoveArrayPrim(Type)) {
303  assert(Source && "Missing source");
304 }
305 
306 /// Arrays of composite elements.
308  unsigned NumElems, bool IsConst, bool IsTemporary,
309  bool IsMutable)
310  : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
311  Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
312  AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
313  ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
314  IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
315  DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
316  assert(Source && "Missing source");
317 }
318 
319 /// Unknown-size arrays of composite elements.
321  bool IsTemporary, UnknownSize)
322  : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
323  Size(UnknownSizeMark), MDSize(MD.value_or(0)),
324  AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),
325  IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
326  CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
327  assert(Source && "Missing source");
328 }
329 
330 /// Composite records.
332  bool IsConst, bool IsTemporary, bool IsMutable)
333  : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
334  Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
335  ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
336  IsTemporary(IsTemporary), CtorFn(ctorRecord), DtorFn(dtorRecord),
337  MoveFn(moveRecord) {
338  assert(Source && "Missing source");
339 }
340 
341 /// Dummy.
343  : Source(D), ElemSize(1), Size(1), MDSize(0), AllocSize(MDSize),
344  ElemRecord(nullptr), IsConst(true), IsMutable(false), IsTemporary(false),
345  IsDummy(true) {
346  assert(Source && "Missing source");
347 }
348 
350  if (auto *E = asExpr())
351  return E->getType();
352  if (auto *D = asValueDecl())
353  return D->getType();
354  if (auto *T = dyn_cast<TypeDecl>(asDecl()))
355  return QualType(T->getTypeForDecl(), 0);
356  llvm_unreachable("Invalid descriptor type");
357 }
358 
360  assert(isArray());
361  const auto *AT = cast<ArrayType>(getType());
362  return AT->getElementType();
363 }
364 
366  if (auto *D = Source.dyn_cast<const Decl *>())
367  return D->getLocation();
368  if (auto *E = Source.dyn_cast<const Expr *>())
369  return E->getExprLoc();
370  llvm_unreachable("Invalid descriptor type");
371 }
372 
373 InitMap::InitMap(unsigned N)
374  : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {
375  std::fill_n(data(), numFields(N), 0);
376 }
377 
378 bool InitMap::initializeElement(unsigned I) {
379  unsigned Bucket = I / PER_FIELD;
380  T Mask = T(1) << (I % PER_FIELD);
381  if (!(data()[Bucket] & Mask)) {
382  data()[Bucket] |= Mask;
383  UninitFields -= 1;
384  }
385  return UninitFields == 0;
386 }
387 
388 bool InitMap::isElementInitialized(unsigned I) const {
389  unsigned Bucket = I / PER_FIELD;
390  return data()[Bucket] & (T(1) << (I % PER_FIELD));
391 }
#define V(N, I)
Definition: ASTContext.h:3299
static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsActive, const Descriptor *D, unsigned FieldOffset, bool IsVirtualBase)
Definition: Descriptor.cpp:156
static void dtorTy(Block *, std::byte *Ptr, const Descriptor *)
Definition: Descriptor.cpp:28
static BlockCtorFn getCtorArrayPrim(PrimType Type)
Definition: Descriptor.cpp:254
static BlockMoveFn getMoveArrayPrim(PrimType Type)
Definition: Descriptor.cpp:264
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D)
Definition: Descriptor.cpp:52
static BlockMoveFn getMovePrim(PrimType Type)
Definition: Descriptor.cpp:250
static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, const Descriptor *)
Definition: Descriptor.cpp:22
static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsActive, bool IsUnion, const Descriptor *D, unsigned FieldOffset)
Definition: Descriptor.cpp:139
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, const Descriptor *D)
Definition: Descriptor.cpp:41
static void moveRecord(Block *B, const std::byte *Src, std::byte *Dst, const Descriptor *D)
Definition: Descriptor.cpp:213
static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D)
Definition: Descriptor.cpp:102
static void moveTy(Block *, const std::byte *Src, std::byte *Dst, const Descriptor *)
Definition: Descriptor.cpp:33
static BlockDtorFn getDtorPrim(PrimType Type)
Definition: Descriptor.cpp:237
static BlockCtorFn getCtorPrim(PrimType Type)
Definition: Descriptor.cpp:224
static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsActive, const Descriptor *D)
Definition: Descriptor.cpp:76
static BlockDtorFn getDtorArrayPrim(PrimType Type)
Definition: Descriptor.cpp:259
static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst, const Descriptor *D)
Definition: Descriptor.cpp:117
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsActive, const Descriptor *D)
Definition: Descriptor.cpp:190
static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D)
Definition: Descriptor.cpp:200
static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst, const Descriptor *D)
Definition: Descriptor.cpp:64
#define COMPOSITE_TYPE_SWITCH(Expr, B, D)
Definition: PrimType.h:174
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:117
const char * Data
__DEVICE__ int max(int __a, int __b)
__SIZE_TYPE__ size_t
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
This represents one expression.
Definition: Expr.h:110
A (possibly-)qualified type.
Definition: Type.h:940
Encodes a location in the source.
The base class of the type hierarchy.
Definition: Type.h:1813
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
Structure/Class descriptor.
Definition: Record.h:25
bool isUnion() const
Checks if the record is a union.
Definition: Record.h:56
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:85
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:77
llvm::iterator_range< const_virtual_iter > virtual_bases() const
Definition: Record.h:96
std::optional< std::pair< bool, std::shared_ptr< InitMap > >> InitMapPtr
Definition: Descriptor.h:28
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:869
void(*)(Block *Storage, std::byte *FieldPtr, const Descriptor *FieldDesc) BlockDtorFn
Invoked when a block is destroyed.
Definition: Descriptor.h:40
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:99
unsigned llvm::PointerUnion< const Decl *, const Expr * > DeclTy
Definition: Descriptor.h:27
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:32
void(*)(Block *Storage, const std::byte *SrcFieldPtr, std::byte *DstFieldPtr, const Descriptor *FieldDesc) BlockMoveFn
Invoked when a block with pointers referencing it goes out of scope.
Definition: Descriptor.h:48
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:22
void(*)(Block *Storage, std::byte *FieldPtr, bool IsConst, bool IsMutable, bool IsActive, const Descriptor *FieldDesc) BlockCtorFn
Invoked whenever a block is created.
Definition: Descriptor.h:35
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Definition: Format.h:5433
#define true
Definition: stdbool.h:25
#define false
Definition: stdbool.h:26
Token to denote structures of unknown size.
Definition: Descriptor.h:109
Describes a memory block created by an allocation site.
Definition: Descriptor.h:91
const bool IsConst
Flag indicating if the block is mutable.
Definition: Descriptor.h:123
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition: Descriptor.h:204
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:211
QualType getElemQualType() const
Definition: Descriptor.cpp:359
const BlockMoveFn MoveFn
Definition: Descriptor.h:136
const Expr * asExpr() const
Definition: Descriptor.h:173
const BlockDtorFn DtorFn
Definition: Descriptor.h:135
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:176
const BlockCtorFn CtorFn
Storage management methods.
Definition: Descriptor.h:134
const Decl * asDecl() const
Definition: Descriptor.h:172
QualType getType() const
Definition: Descriptor.cpp:349
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition: Descriptor.h:117
SourceLocation getLocation() const
Definition: Descriptor.cpp:365
const bool IsMutable
Flag indicating if a field is mutable.
Definition: Descriptor.h:125
std::optional< unsigned > MetadataSize
Definition: Descriptor.h:111
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:129
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable)
Allocates a descriptor for a primitive.
Definition: Descriptor.cpp:270
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:115
bool isArray() const
Checks if the descriptor is of an array.
Definition: Descriptor.h:228
InitMap(unsigned N)
Initializes the map with no fields set.
Definition: Descriptor.cpp:373
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:56
unsigned Offset
Offset inside the structure/array.
Definition: Descriptor.h:58