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