Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Descriptor.h
213799 views
//===--- Descriptor.h - Types for the constexpr VM --------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines descriptors which characterise allocations.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H13#define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H1415#include "PrimType.h"16#include "clang/AST/Decl.h"17#include "clang/AST/Expr.h"1819namespace clang {20namespace interp {21class Block;22class Record;23class SourceInfo;24struct InitMap;25struct Descriptor;26enum PrimType : unsigned;2728using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;29using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;3031/// Invoked whenever a block is created. The constructor method fills in the32/// inline descriptors of all fields and array elements. It also initializes33/// all the fields which contain non-trivial types.34using BlockCtorFn = void (*)(Block *Storage, std::byte *FieldPtr, bool IsConst,35bool IsMutable, bool IsVolatile, bool IsActive,36bool InUnion, const Descriptor *FieldDesc);3738/// Invoked when a block is destroyed. Invokes the destructors of all39/// non-trivial nested fields of arrays and records.40using BlockDtorFn = void (*)(Block *Storage, std::byte *FieldPtr,41const Descriptor *FieldDesc);4243/// Invoked when a block with pointers referencing it goes out of scope. Such44/// blocks are persisted: the move function copies all inline descriptors and45/// non-trivial fields, as existing pointers might need to reference those46/// descriptors. Data is not copied since it cannot be legally read.47using BlockMoveFn = void (*)(Block *Storage, std::byte *SrcFieldPtr,48std::byte *DstFieldPtr,49const Descriptor *FieldDesc);5051enum class GlobalInitState {52Initialized,53NoInitializer,54InitializerFailed,55};5657/// Descriptor used for global variables.58struct alignas(void *) GlobalInlineDescriptor {59GlobalInitState InitState = GlobalInitState::InitializerFailed;60};61static_assert(sizeof(GlobalInlineDescriptor) == sizeof(void *), "");6263enum class Lifetime : uint8_t {64Started,65Ended,66};6768/// Inline descriptor embedded in structures and arrays.69///70/// Such descriptors precede all composite array elements and structure fields.71/// If the base of a pointer is not zero, the base points to the end of this72/// structure. The offset field is used to traverse the pointer chain up73/// to the root structure which allocated the object.74struct InlineDescriptor {75/// Offset inside the structure/array.76unsigned Offset;7778/// Flag indicating if the storage is constant or not.79/// Relevant for primitive fields.80LLVM_PREFERRED_TYPE(bool)81unsigned IsConst : 1;82/// For primitive fields, it indicates if the field was initialized.83/// Primitive fields in static storage are always initialized.84/// Arrays are always initialized, even though their elements might not be.85/// Base classes are initialized after the constructor is invoked.86LLVM_PREFERRED_TYPE(bool)87unsigned IsInitialized : 1;88/// Flag indicating if the field is an embedded base class.89LLVM_PREFERRED_TYPE(bool)90unsigned IsBase : 1;91/// Flag inidcating if the field is a virtual base class.92LLVM_PREFERRED_TYPE(bool)93unsigned IsVirtualBase : 1;94/// Flag indicating if the field is the active member of a union.95LLVM_PREFERRED_TYPE(bool)96unsigned IsActive : 1;97/// Flag indicating if this field is in a union (even if nested).98LLVM_PREFERRED_TYPE(bool)99unsigned InUnion : 1;100/// Flag indicating if the field is mutable (if in a record).101LLVM_PREFERRED_TYPE(bool)102unsigned IsFieldMutable : 1;103/// Flag indicating if the field is an element of a composite array.104LLVM_PREFERRED_TYPE(bool)105unsigned IsArrayElement : 1;106LLVM_PREFERRED_TYPE(bool)107unsigned IsVolatile : 1;108109Lifetime LifeState;110111const Descriptor *Desc;112113InlineDescriptor(const Descriptor *D)114: Offset(sizeof(InlineDescriptor)), IsConst(false), IsInitialized(false),115IsBase(false), IsActive(false), IsFieldMutable(false),116IsArrayElement(false), IsVolatile(false), LifeState(Lifetime::Started),117Desc(D) {}118119void dump() const { dump(llvm::errs()); }120void dump(llvm::raw_ostream &OS) const;121};122static_assert(sizeof(GlobalInlineDescriptor) != sizeof(InlineDescriptor), "");123124/// Describes a memory block created by an allocation site.125struct Descriptor final {126private:127/// Original declaration, used to emit the error message.128const DeclTy Source;129const Type *SourceType = nullptr;130/// Size of an element, in host bytes.131const unsigned ElemSize;132/// Size of the storage, in host bytes.133const unsigned Size;134/// Size of the metadata.135const unsigned MDSize;136/// Size of the allocation (storage + metadata), in host bytes.137const unsigned AllocSize;138139/// Value to denote arrays of unknown size.140static constexpr unsigned UnknownSizeMark = (unsigned)-1;141142public:143/// Token to denote structures of unknown size.144struct UnknownSize {};145146using MetadataSize = std::optional<unsigned>;147static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor);148static constexpr MetadataSize GlobalMD = sizeof(GlobalInlineDescriptor);149150/// Maximum number of bytes to be used for array elements.151static constexpr unsigned MaxArrayElemBytes =152std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMapPtr) -153align(std::max(*InlineDescMD, *GlobalMD));154155/// Pointer to the record, if block contains records.156const Record *const ElemRecord = nullptr;157/// Descriptor of the array element.158const Descriptor *const ElemDesc = nullptr;159/// The primitive type this descriptor was created for,160/// or the primitive element type in case this is161/// a primitive array.162const std::optional<PrimType> PrimT = std::nullopt;163/// Flag indicating if the block is mutable.164const bool IsConst = false;165/// Flag indicating if a field is mutable.166const bool IsMutable = false;167/// Flag indicating if the block is a temporary.168const bool IsTemporary = false;169const bool IsVolatile = false;170/// Flag indicating if the block is an array.171const bool IsArray = false;172/// Flag indicating if this is a dummy descriptor.173bool IsDummy = false;174bool IsConstexprUnknown = false;175176/// Storage management methods.177const BlockCtorFn CtorFn = nullptr;178const BlockDtorFn DtorFn = nullptr;179const BlockMoveFn MoveFn = nullptr;180181/// Allocates a descriptor for a primitive.182Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,183MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable,184bool IsVolatile);185186/// Allocates a descriptor for an array of primitives.187Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, size_t NumElems,188bool IsConst, bool IsTemporary, bool IsMutable);189190/// Allocates a descriptor for an array of primitives of unknown size.191Descriptor(const DeclTy &D, PrimType Type, MetadataSize MDSize, bool IsConst,192bool IsTemporary, UnknownSize);193194/// Allocates a descriptor for an array of composites.195Descriptor(const DeclTy &D, const Type *SourceTy, const Descriptor *Elem,196MetadataSize MD, unsigned NumElems, bool IsConst, bool IsTemporary,197bool IsMutable);198199/// Allocates a descriptor for an array of composites of unknown size.200Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,201bool IsTemporary, UnknownSize);202203/// Allocates a descriptor for a record.204Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,205bool IsTemporary, bool IsMutable, bool IsVolatile);206207/// Allocates a dummy descriptor.208Descriptor(const DeclTy &D, MetadataSize MD = std::nullopt);209210/// Make this descriptor a dummy descriptor.211void makeDummy() { IsDummy = true; }212213QualType getType() const;214QualType getElemQualType() const;215QualType getDataType(const ASTContext &Ctx) const;216SourceLocation getLocation() const;217SourceInfo getLoc() const;218219const Decl *asDecl() const { return dyn_cast<const Decl *>(Source); }220const Expr *asExpr() const { return dyn_cast<const Expr *>(Source); }221const DeclTy &getSource() const { return Source; }222223const ValueDecl *asValueDecl() const {224return dyn_cast_if_present<ValueDecl>(asDecl());225}226227const VarDecl *asVarDecl() const {228return dyn_cast_if_present<VarDecl>(asDecl());229}230231const FieldDecl *asFieldDecl() const {232return dyn_cast_if_present<FieldDecl>(asDecl());233}234235const RecordDecl *asRecordDecl() const {236return dyn_cast_if_present<RecordDecl>(asDecl());237}238239/// Returns the size of the object without metadata.240unsigned getSize() const {241assert(!isUnknownSizeArray() && "Array of unknown size");242return Size;243}244245PrimType getPrimType() const {246assert(isPrimitiveArray() || isPrimitive());247return *PrimT;248}249250/// Returns the allocated size, including metadata.251unsigned getAllocSize() const { return AllocSize; }252/// returns the size of an element when the structure is viewed as an array.253unsigned getElemSize() const { return ElemSize; }254/// Returns the size of the metadata.255unsigned getMetadataSize() const { return MDSize; }256257/// Returns the number of elements stored in the block.258unsigned getNumElems() const {259return Size == UnknownSizeMark ? 0 : (getSize() / getElemSize());260}261262/// Checks if the descriptor is of an array of primitives.263bool isPrimitiveArray() const { return IsArray && !ElemDesc; }264/// Checks if the descriptor is of an array of composites.265bool isCompositeArray() const { return IsArray && ElemDesc; }266/// Checks if the descriptor is of an array of zero size.267bool isZeroSizeArray() const { return Size == 0; }268/// Checks if the descriptor is of an array of unknown size.269bool isUnknownSizeArray() const { return Size == UnknownSizeMark; }270271/// Checks if the descriptor is of a primitive.272bool isPrimitive() const { return !IsArray && !ElemRecord && PrimT; }273274/// Checks if the descriptor is of an array.275bool isArray() const { return IsArray; }276/// Checks if the descriptor is of a record.277bool isRecord() const { return !IsArray && ElemRecord; }278/// Checks if the descriptor is of a union.279bool isUnion() const;280/// Checks if this is a dummy descriptor.281bool isDummy() const { return IsDummy; }282283/// Whether variables of this descriptor need their destructor called or not.284bool hasTrivialDtor() const;285286void dump() const;287void dump(llvm::raw_ostream &OS) const;288void dumpFull(unsigned Offset = 0, unsigned Indent = 0) const;289};290291/// Bitfield tracking the initialisation status of elements of primitive arrays.292struct InitMap final {293private:294/// Type packing bits.295using T = uint64_t;296/// Bits stored in a single field.297static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT;298299public:300/// Initializes the map with no fields set.301explicit InitMap(unsigned N);302303private:304friend class Pointer;305306/// Returns a pointer to storage.307T *data() { return Data.get(); }308const T *data() const { return Data.get(); }309310/// Initializes an element. Returns true when object if fully initialized.311bool initializeElement(unsigned I);312313/// Checks if an element was initialized.314bool isElementInitialized(unsigned I) const;315316static constexpr size_t numFields(unsigned N) {317return (N + PER_FIELD - 1) / PER_FIELD;318}319/// Number of fields not initialized.320unsigned UninitFields;321std::unique_ptr<T[]> Data;322};323324} // namespace interp325} // namespace clang326327#endif328329330