25#include "llvm/Support/ErrorHandling.h"
30template <
typename T>
static constexpr bool needsDtor() {
31 return std::is_same_v<T, Pointer> || std::is_same_v<T, MemberPointer>;
37 reinterpret_cast<T *
>(Ptr)->~
T();
48 reinterpret_cast<T *
>(Ptr)[I].~
T();
54 bool IsMutable,
bool IsVolatile,
bool IsActive,
57 const unsigned ElemSize =
60 unsigned ElemOffset = 0;
61 for (
unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
62 auto *ElemPtr = Ptr + ElemOffset;
68 Desc->IsInitialized =
true;
70 Desc->IsActive = IsActive;
71 Desc->IsConst = IsConst || D->
IsConst;
72 Desc->IsFieldMutable = IsMutable || D->
IsMutable;
73 Desc->InUnion = InUnion;
74 Desc->IsArrayElement =
true;
75 Desc->IsVolatile = IsVolatile;
78 auto *ElemLoc =
reinterpret_cast<std::byte *
>(Desc + 1);
79 Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,
80 Desc->InUnion || SD->isUnion(), D->
ElemDesc);
87 const unsigned ElemSize =
90 unsigned ElemOffset = 0;
93 "a composite array without an elem dtor shouldn't have a dtor itself");
94 for (
unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
95 auto *ElemPtr = Ptr + ElemOffset;
97 auto *ElemLoc =
reinterpret_cast<std::byte *
>(Desc + 1);
103 bool IsVolatile,
bool IsActive,
bool IsUnionField,
104 bool InUnion,
const Descriptor *D,
unsigned FieldOffset) {
106 Desc->
Offset = FieldOffset;
108 Desc->IsInitialized = D->
IsArray;
109 Desc->IsBase =
false;
110 Desc->IsActive = IsActive && !IsUnionField;
111 Desc->InUnion = InUnion;
112 Desc->IsConst = IsConst || D->
IsConst;
113 Desc->IsFieldMutable = IsMutable || D->
IsMutable;
114 Desc->IsVolatile = IsVolatile || D->
IsVolatile;
116 Desc->IsConstInMutable = Desc->IsConst && IsMutable;
123 Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
124 Desc->IsVolatile, Desc->IsActive, InUnion || D->
isUnion(), D);
128 bool IsVolatile,
bool IsActive,
bool InUnion,
130 bool IsVirtualBase) {
136 Desc->
Offset = FieldOffset;
138 Desc->IsInitialized = D->
IsArray;
140 Desc->IsVirtualBase = IsVirtualBase;
141 Desc->IsActive = IsActive && !InUnion;
142 Desc->IsConst = IsConst || D->
IsConst;
143 Desc->IsFieldMutable = IsMutable || D->
IsMutable;
144 Desc->InUnion = InUnion;
145 Desc->IsVolatile =
false;
148 initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
149 InUnion,
V.Desc,
V.Offset,
false);
151 initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
152 InUnion, InUnion, F.Desc, F.Offset);
156 bool IsVolatile,
bool IsActive,
bool InUnion,
159 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion,
V.Desc,
163 bool IsUnionField = D->
isUnion();
164 initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,
165 InUnion || IsUnionField, F.Desc, F.Offset);
168 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion,
V.Desc,
174 unsigned FieldOffset) {
176 Fn(B, Ptr + FieldOffset, D);
180 unsigned FieldOffset) {
201 for (
const auto &B : R->bases()) {
206 for (
const auto &F : R->fields()) {
211 for (
const auto &
V : R->virtual_bases()) {
227 llvm_unreachable(
"Unhandled PrimType");
234template <
typename T>
static constexpr bool needsCtor() {
236 if constexpr (std::is_same_v<T, Char<true>> ||
237 std::is_same_v<T, Char<false>> ||
238 std::is_same_v<T, Integral<16, true>> ||
239 std::is_same_v<T, Integral<16, false>> ||
240 std::is_same_v<T, Integral<32, true>> ||
241 std::is_same_v<T, Integral<32, false>> ||
242 std::is_same_v<T, Integral<64, true>> ||
243 std::is_same_v<T, Integral<64, false>> ||
244 std::is_same_v<T, IntegralAP<true>> ||
245 std::is_same_v<T, IntegralAP<false>> ||
246 std::is_same_v<T, Floating> || std::is_same_v<T, Boolean>)
255 return ctorArrayTy<T>);
256 llvm_unreachable(
"unknown Expr");
268 llvm_unreachable(
"Unhandled PrimType");
273static void ctorArrayTy(
Block *, std::byte *Ptr,
bool,
bool,
bool,
bool,
bool,
277 if constexpr (needsCtor<T>()) {
280 new (&
reinterpret_cast<T *
>(
Ptr)[I])
T();
285static void ctorTy(
Block *, std::byte *Ptr,
bool,
bool,
bool,
bool,
bool,
287 static_assert(needsCtor<T>());
294 llvm_unreachable(
"unknown Expr");
301 : Source(D), SourceType(SourceTy), ElemSize(
primSize(
Type)), Size(ElemSize),
305 assert(Source &&
"Missing source");
312 : Source(D), SourceType(SourceTy), ElemSize(
primSize(
Type)),
313 Size(ElemSize * NumElems), AllocSize(
align(Size) + sizeof(
InitMapPtr)),
317 assert(Source &&
"Missing source");
324 : Source(D), ElemSize(
primSize(
Type)), Size(UnknownSizeMark),
328 assert(Source &&
"Missing source");
335 : Source(D), SourceType(SourceTy),
337 Size(ElemSize * NumElems),
342 assert(Source &&
"Missing source");
349 Size(UnknownSizeMark), AllocSize(alignof(void *)),
ElemDesc(Elem),
352 assert(Source &&
"Missing source");
358 : Source(D), ElemSize(
std::
max<
size_t>(alignof(void *), R->getFullSize())),
362 assert(Source &&
"Missing source");
369 assert(Source &&
"Missing source");
376 if (
const auto *
T = dyn_cast_if_present<TypeDecl>(
asDecl()))
377 return T->getASTContext().getTypeDeclType(
T);
384 std::nullopt, RD,
false);
386 return T.withConst();
390 if (
const auto *E =
asExpr()) {
392 return E->getType()->getPointeeType();
395 if (
const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
396 ME && ME->getRecordDecl()->getName() ==
"allocator" &&
397 ME->getMethodDecl()->getName() ==
"allocate")
398 return E->getType()->getPointeeType();
405 llvm_unreachable(
"Invalid descriptor type");
414 }
else if (
const auto *TDecl = dyn_cast_if_present<TypeDecl>(
asDecl())) {
415 T = TDecl->getASTContext().getTypeDeclType(TDecl);
419 std::nullopt, RD,
false);
422 }
else if (
const auto *E =
asExpr()) {
431 T = AT->getValueType();
432 if (
T->isPointerOrReferenceType())
433 T =
T->getPointeeType();
435 if (
const auto *AT =
T->getAsArrayTypeUnsafe()) {
439 while (
T->isArrayType())
440 T =
T->getAsArrayTypeUnsafe()->getElementType();
443 return AT->getElementType();
446 return CT->getElementType();
448 return CT->getElementType();
469 if (
const auto *D = Source.
asDecl())
471 if (
const auto *E = Source.asExpr())
473 llvm_unreachable(
"Invalid descriptor type");
505 if (
const auto *
NE = dyn_cast<CXXNewExpr>(E))
508 if (
const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
509 ME && ME->getRecordDecl()->getName() ==
"allocator" &&
510 ME->getMethodDecl()->getName() ==
"allocate")
513 if (
const auto *CE = dyn_cast<CallExpr>(E);
514 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
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 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 constexpr bool needsDtor()
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 void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D)
static bool needsRecordDtor(const Record *R)
Whether a record needs its descriptor dtor function called.
static BlockDtorFn getDtorArrayPrim(PrimType Type)
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 FIXED_SIZE_INT_TYPE_SWITCH(Expr, B)
#define TYPE_SWITCH(Expr, B)
static QualType getPointeeType(const MemRegion *R)
__DEVICE__ int max(int __a, int __b)
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
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.
QualType getTagType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag) const
This is an opaque type for sizes expressed in character units.
Complex values, per C99 6.2.5p11.
ASTContext & getASTContext() const LLVM_READONLY
This represents one expression.
A (possibly-)qualified type.
Represents a struct/union/class.
The base class of the type hierarchy.
Represents a GCC generic vector type.
A memory block, either on the stack or in the heap.
Structure/Class descriptor.
bool isUnion() const
Checks if the record is a union.
llvm::iterator_range< const_base_iter > bases() const
llvm::iterator_range< const_base_iter > virtual_bases() const
llvm::iterator_range< const_field_iter > fields() const
Describes the statement/declaration an opcode was generated from.
Defines the clang::TargetInfo interface.
void(*)(Block *Storage, std::byte *FieldPtr, const Descriptor *FieldDesc) BlockDtorFn
Invoked when a block is destroyed.
bool NE(InterpState &S, CodePtr OpPC)
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
constexpr bool isIntegerOrBoolType(PrimType T)
PrimType
Enumeration of the primitive types of the VM.
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
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.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
DynAllocKind
Kind of source for a dynamic allocation.
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
const FunctionProtoType * T
@ None
No keyword precedes the qualified type name.
CharUnits GetAlignOfDynamicAlloc(const ASTContext &Ctx, QualType AllocType, DynAllocKind AllocKind)
Token to denote structures of unknown size.
Describes a memory block created by an allocation site.
const bool IsConst
Flag indicating if the block is mutable.
unsigned getAllocSize() const
Returns the allocated size, including metadata.
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 OptPrimType PrimT
The primitive type this descriptor was created for, or the primitive element type in case this is a p...
const ValueDecl * asValueDecl() const
const BlockCtorFn CtorFn
Storage management methods.
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
const bool IsMutable
Flag indicating if a field is mutable.
QualType getDataType(const ASTContext &Ctx) const
bool isDynAlloc() const
Checks if the descriptor is of a dynamic allocation.
static DynAllocKind getDynAllocKindForExpr(const Expr *E)
Returns the kind of dynamic allocation source of this block.
const bool IsArray
Flag indicating if the block is an array.
unsigned getElemDataSize() const
Returns the element data size, i.e.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
DynAllocKind getDynAllocKind() const
Returns the kind of dynamic allocation source of this block.
Descriptor(DeclOrExpr D, const Type *SourceTy, PrimType Type, bool IsConst, bool IsTemporary, bool IsMutable, bool IsVolatile)
Allocates a descriptor for a primitive.
PrimType getPrimType() const
CharUnits computeAlignForDynamicAlloc(const ASTContext &Ctx) const
Compute the alignment for a dynamic allocation.
bool isRecord() const
Checks if the descriptor is of a record.
const bool IsTemporary
Flag indicating if the block is a temporary.
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.
A pointer-sized struct we use to allocate into data storage.
void deleteInitMap()
Delete the InitMap if one exists.
Inline descriptor embedded in structures and arrays.
unsigned Offset
Offset inside the structure/array.