24template <
typename T>
static constexpr bool needsCtor() {
25 if constexpr (std::is_same_v<T, Integral<8, true>> ||
26 std::is_same_v<T, Integral<8, false>> ||
27 std::is_same_v<T, Integral<16, true>> ||
28 std::is_same_v<T, Integral<16, false>> ||
29 std::is_same_v<T, Integral<32, true>> ||
30 std::is_same_v<T, Integral<32, false>> ||
31 std::is_same_v<T, Integral<64, true>> ||
32 std::is_same_v<T, Integral<64, false>> ||
33 std::is_same_v<T, Boolean>)
40static void ctorTy(
Block *, std::byte *Ptr,
bool,
bool,
bool,
bool,
bool,
42 static_assert(needsCtor<T>());
48 static_assert(needsCtor<T>());
49 reinterpret_cast<T *
>(Ptr)->~
T();
57 if constexpr (needsCtor<T>()) {
59 for (
unsigned I = 0,
NE =
D->getNumElems(); I <
NE; ++I) {
60 new (&
reinterpret_cast<T *
>(Ptr)[I])
T();
72 if constexpr (needsCtor<T>()) {
74 for (
unsigned I = 0,
NE =
D->getNumElems(); I <
NE; ++I) {
75 reinterpret_cast<T *
>(Ptr)[I].~
T();
81 bool IsMutable,
bool IsVolatile,
bool IsActive,
83 const unsigned NumElems =
D->getNumElems();
84 const unsigned ElemSize =
87 unsigned ElemOffset = 0;
88 for (
unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
89 auto *ElemPtr = Ptr + ElemOffset;
91 auto *ElemLoc =
reinterpret_cast<std::byte *
>(Desc + 1);
92 auto *SD =
D->ElemDesc;
96 Desc->IsInitialized =
true;
98 Desc->IsActive = IsActive;
99 Desc->IsConst = IsConst ||
D->IsConst;
100 Desc->IsFieldMutable = IsMutable ||
D->IsMutable;
101 Desc->InUnion = InUnion;
102 Desc->IsArrayElement =
true;
103 Desc->IsVolatile = IsVolatile;
105 if (
auto Fn =
D->ElemDesc->CtorFn)
106 Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,
107 Desc->InUnion || SD->isUnion(),
D->ElemDesc);
112 const unsigned NumElems =
D->getNumElems();
113 const unsigned ElemSize =
116 unsigned ElemOffset = 0;
117 auto Dtor =
D->ElemDesc->DtorFn;
119 "a composite array without an elem dtor shouldn't have a dtor itself");
120 for (
unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
121 auto *ElemPtr = Ptr + ElemOffset;
123 auto *ElemLoc =
reinterpret_cast<std::byte *
>(Desc + 1);
124 Dtor(B, ElemLoc,
D->ElemDesc);
129 bool IsVolatile,
bool IsActive,
bool IsUnionField,
130 bool InUnion,
const Descriptor *
D,
unsigned FieldOffset) {
132 Desc->
Offset = FieldOffset;
134 Desc->IsInitialized =
D->IsArray;
135 Desc->IsBase =
false;
136 Desc->IsActive = IsActive && !IsUnionField;
137 Desc->InUnion = InUnion;
138 Desc->IsConst = IsConst ||
D->IsConst;
139 Desc->IsFieldMutable = IsMutable ||
D->IsMutable;
140 Desc->IsVolatile = IsVolatile ||
D->IsVolatile;
142 Desc->IsConstInMutable = Desc->IsConst && IsMutable;
144 if (
auto Fn =
D->CtorFn)
145 Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
146 Desc->IsVolatile, Desc->IsActive, InUnion ||
D->isUnion(),
D);
150 bool IsVolatile,
bool IsActive,
bool InUnion,
152 bool IsVirtualBase) {
154 assert(
D->ElemRecord);
155 assert(!
D->ElemRecord->isUnion());
158 Desc->
Offset = FieldOffset;
160 Desc->IsInitialized =
D->IsArray;
162 Desc->IsVirtualBase = IsVirtualBase;
163 Desc->IsActive = IsActive && !InUnion;
164 Desc->IsConst = IsConst ||
D->IsConst;
165 Desc->IsFieldMutable = IsMutable ||
D->IsMutable;
166 Desc->InUnion = InUnion;
167 Desc->IsVolatile =
false;
169 for (
const auto &
V :
D->ElemRecord->bases())
170 initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
171 InUnion,
V.Desc,
V.Offset,
false);
172 for (
const auto &F :
D->ElemRecord->fields())
173 initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
174 InUnion, InUnion, F.Desc, F.Offset);
178 bool IsVolatile,
bool IsActive,
bool InUnion,
180 for (
const auto &
V :
D->ElemRecord->bases())
181 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion,
V.Desc,
184 for (
const auto &F :
D->ElemRecord->fields()) {
185 bool IsUnionField =
D->isUnion();
186 initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,
187 InUnion || IsUnionField, F.Desc, F.Offset);
189 for (
const auto &
V :
D->ElemRecord->virtual_bases())
190 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion,
V.Desc,
196 unsigned FieldOffset) {
197 if (
auto Fn =
D->DtorFn)
198 Fn(B, Ptr + FieldOffset,
D);
202 unsigned FieldOffset) {
204 assert(
D->ElemRecord);
206 for (
const auto &
V :
D->ElemRecord->bases())
208 for (
const auto &F :
D->ElemRecord->fields())
213 for (
const auto &F :
D->ElemRecord->bases())
215 for (
const auto &F :
D->ElemRecord->fields())
217 for (
const auto &F :
D->ElemRecord->virtual_bases())
223 for (
const auto &B : R->
bases()) {
228 for (
const auto &F : R->
fields()) {
243 return ctorTy<PrimConv<PT_Float>::T>;
245 return ctorTy<PrimConv<PT_IntAP>::T>;
247 return ctorTy<PrimConv<PT_IntAPS>::T>;
249 return ctorTy<PrimConv<PT_Ptr>::T>;
251 return ctorTy<PrimConv<PT_MemberPtr>::T>;
255 llvm_unreachable(
"Unhandled PrimType");
261 return dtorTy<PrimConv<PT_Float>::T>;
263 return dtorTy<PrimConv<PT_IntAP>::T>;
265 return dtorTy<PrimConv<PT_IntAPS>::T>;
267 return dtorTy<PrimConv<PT_Ptr>::T>;
269 return dtorTy<PrimConv<PT_MemberPtr>::T>;
273 llvm_unreachable(
"Unhandled PrimType");
278 llvm_unreachable(
"unknown Expr");
283 llvm_unreachable(
"unknown Expr");
289 bool IsMutable,
bool IsVolatile)
290 : Source(
D), SourceType(SourceTy), ElemSize(
primSize(
Type)), Size(ElemSize),
291 MDSize(MD.value_or(0)), AllocSize(
align(Size + MDSize)), PrimT(
Type),
292 IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
295 assert(AllocSize >= Size);
296 assert(Source &&
"Missing source");
301 size_t NumElems,
bool IsConst,
bool IsTemporary,
303 : Source(
D), ElemSize(
primSize(
Type)), Size(ElemSize * NumElems),
304 MDSize(MD.value_or(0)),
306 IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
309 assert(Source &&
"Missing source");
316 : Source(
D), ElemSize(
primSize(
Type)), Size(UnknownSizeMark),
317 MDSize(MD.value_or(0)),
318 AllocSize(MDSize + sizeof(
InitMapPtr) + alignof(void *)), PrimT(
Type),
319 IsConst(IsConst), IsMutable(
false), IsTemporary(IsTemporary),
322 assert(Source &&
"Missing source");
328 unsigned NumElems,
bool IsConst,
bool IsTemporary,
330 : Source(
D), SourceType(SourceTy),
332 Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
333 AllocSize(
std::
max<
size_t>(alignof(void *), Size) + MDSize),
334 ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
337 assert(Source &&
"Missing source");
344 Size(UnknownSizeMark), MDSize(MD.value_or(0)),
345 AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(
true),
346 IsMutable(
false), IsTemporary(IsTemporary), IsArray(
true),
348 assert(Source &&
"Missing source");
353 bool IsConst,
bool IsTemporary,
bool IsMutable,
355 : Source(
D), ElemSize(
std::
max<
size_t>(alignof(void *), R->getFullSize())),
356 Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
357 ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
358 IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(
ctorRecord),
360 assert(Source &&
"Missing source");
365 : Source(
D), ElemSize(1), Size(1), MDSize(MD.value_or(0)),
366 AllocSize(MDSize), ElemRecord(nullptr), IsConst(
true), IsMutable(
false),
368 assert(Source &&
"Missing source");
376 if (
const auto *
T = dyn_cast_if_present<TypeDecl>(
asDecl()))
377 return T->getASTContext().getTypeDeclType(
T);
387 llvm_unreachable(
"Invalid descriptor type");
404 return AT->getElementType();
407 return CT->getElementType();
409 return CT->getElementType();
423 if (
const auto *
E =
asExpr()) {
424 if (isa<CXXNewExpr>(
E))
428 if (
const auto *ME = dyn_cast<CXXMemberCallExpr>(
E);
429 ME && ME->getRecordDecl()->getName() ==
"allocator" &&
430 ME->getMethodDecl()->getName() ==
"allocate")
439 if (
auto *
D = dyn_cast<const Decl *>(Source))
441 if (
auto *
E = dyn_cast<const Expr *>(Source))
443 llvm_unreachable(
"Invalid descriptor type");
447 if (
const auto *
D = dyn_cast<const Decl *>(Source))
449 if (
const auto *
E = dyn_cast<const Expr *>(Source))
451 llvm_unreachable(
"Invalid descriptor type");
473 : UninitFields(N),
Data(
std::make_unique<T[]>(numFields(N))) {}
475bool InitMap::initializeElement(
unsigned I) {
476 unsigned Bucket = I / PER_FIELD;
477 T Mask = T(1) << (I % PER_FIELD);
478 if (!(data()[Bucket] & Mask)) {
479 data()[Bucket] |= Mask;
482 return UninitFields == 0;
485bool InitMap::isElementInitialized(
unsigned I)
const {
486 unsigned Bucket = I / PER_FIELD;
487 return data()[Bucket] & (T(1) << (I % PER_FIELD));
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *D)
static void dtorTy(Block *, std::byte *Ptr, const Descriptor *)
static BlockCtorFn getCtorArrayPrim(PrimType Type)
static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D, unsigned FieldOffset)
static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool IsUnionField, bool InUnion, const Descriptor *D, unsigned FieldOffset)
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D)
static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *)
static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *D)
static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D, unsigned FieldOffset)
static constexpr bool needsCtor()
static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D)
static BlockCtorFn getCtorPrim(PrimType T)
static bool needsRecordDtor(const Record *R)
Whether a record needs its descriptor dtor function called.
static BlockDtorFn getDtorArrayPrim(PrimType Type)
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *D)
static BlockDtorFn getDtorPrim(PrimType T)
static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D)
static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *D, unsigned FieldOffset, bool IsVirtualBase)
Defines the clang::Expr interface and subclasses for C++ expressions.
#define TYPE_SWITCH(Expr, B)
__DEVICE__ int max(int __a, int __b)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
CanQualType getCanonicalTagType(const TagDecl *TD) const
QualType getElementType() const
Represents a C++ destructor within a class.
Complex values, per C99 6.2.5p11.
ASTContext & getASTContext() const LLVM_READONLY
SourceLocation getLocation() const
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
A (possibly-)qualified type.
Represents a struct/union/class.
Encodes a location in the source.
The base class of the type hierarchy.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
bool isPointerOrReferenceType() const
const T * getAs() const
Member-template getAs<specific type>'.
Represents a GCC generic vector type.
A memory block, either on the stack or in the heap.
Structure/Class descriptor.
const RecordDecl * getDecl() const
Returns the underlying declaration.
bool isUnion() const
Checks if the record is a union.
const CXXDestructorDecl * getDestructor() const
Returns the destructor of the record, if any.
llvm::iterator_range< const_virtual_iter > virtual_bases() const
llvm::iterator_range< const_base_iter > bases() const
llvm::iterator_range< const_field_iter > fields() const
Describes the statement/declaration an opcode was generated from.
void(*)(Block *Storage, std::byte *FieldPtr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *FieldDesc) BlockCtorFn
Invoked whenever a block is created.
std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr
bool NE(InterpState &S, CodePtr OpPC)
void(*)(Block *Storage, std::byte *FieldPtr, const Descriptor *FieldDesc) BlockDtorFn
Invoked when a block is destroyed.
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
PrimType
Enumeration of the primitive types of the VM.
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
llvm::PointerUnion< const Decl *, const Expr * > DeclTy
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Token to denote structures of unknown size.
Describes a memory block created by an allocation site.
unsigned getNumElems() const
Returns the number of elements stored in the block.
bool isPrimitive() const
Checks if the descriptor is of a primitive.
QualType getElemQualType() const
bool hasTrivialDtor() const
Whether variables of this descriptor need their destructor called or not.
const ValueDecl * asValueDecl() const
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
const Decl * asDecl() const
const Descriptor *const ElemDesc
Descriptor of the array element.
SourceInfo getLoc() const
Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type, MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable, bool IsVolatile)
Allocates a descriptor for a primitive.
SourceLocation getLocation() const
QualType getDataType(const ASTContext &Ctx) const
std::optional< unsigned > MetadataSize
const bool IsArray
Flag indicating if the block is an array.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
bool isRecord() const
Checks if the descriptor is of a record.
const Record *const ElemRecord
Pointer to the record, if block contains records.
bool isUnion() const
Checks if the descriptor is of a union.
const Expr * asExpr() const
bool isArray() const
Checks if the descriptor is of an array.
InitMap(unsigned N)
Initializes the map with no fields set.
Inline descriptor embedded in structures and arrays.
unsigned Offset
Offset inside the structure/array.