Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Descriptor.cpp
213799 views
//===--- Descriptor.cpp - 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//===----------------------------------------------------------------------===//78#include "Descriptor.h"9#include "Boolean.h"10#include "FixedPoint.h"11#include "Floating.h"12#include "IntegralAP.h"13#include "MemberPointer.h"14#include "Pointer.h"15#include "PrimType.h"16#include "Record.h"17#include "Source.h"18#include "clang/AST/ExprCXX.h"1920using namespace clang;21using namespace clang::interp;2223template <typename T>24static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,25const Descriptor *) {26new (Ptr) T();27}2829template <typename T>30static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {31reinterpret_cast<T *>(Ptr)->~T();32}3334template <typename T>35static void moveTy(Block *, std::byte *Src, std::byte *Dst,36const Descriptor *) {37auto *SrcPtr = reinterpret_cast<T *>(Src);38auto *DstPtr = reinterpret_cast<T *>(Dst);39new (DstPtr) T(std::move(*SrcPtr));40}4142template <typename T>43static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,44const Descriptor *D) {45new (Ptr) InitMapPtr(std::nullopt);4647Ptr += sizeof(InitMapPtr);48for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {49new (&reinterpret_cast<T *>(Ptr)[I]) T();50}51}5253template <typename T>54static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {55InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);5657if (IMP)58IMP = std::nullopt;59Ptr += sizeof(InitMapPtr);60for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {61reinterpret_cast<T *>(Ptr)[I].~T();62}63}6465template <typename T>66static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst,67const Descriptor *D) {68InitMapPtr &SrcIMP = *reinterpret_cast<InitMapPtr *>(Src);69if (SrcIMP) {70// We only ever invoke the moveFunc when moving block contents to a71// DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here.72SrcIMP = std::nullopt;73}74Src += sizeof(InitMapPtr);75Dst += sizeof(InitMapPtr);76for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {77auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];78auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];79new (DstPtr) T(std::move(*SrcPtr));80}81}8283static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,84bool IsMutable, bool IsVolatile, bool IsActive,85bool InUnion, const Descriptor *D) {86const unsigned NumElems = D->getNumElems();87const unsigned ElemSize =88D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);8990unsigned ElemOffset = 0;91for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {92auto *ElemPtr = Ptr + ElemOffset;93auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);94auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);95auto *SD = D->ElemDesc;9697Desc->Offset = ElemOffset + sizeof(InlineDescriptor);98Desc->Desc = SD;99Desc->IsInitialized = true;100Desc->IsBase = false;101Desc->IsActive = IsActive;102Desc->IsConst = IsConst || D->IsConst;103Desc->IsFieldMutable = IsMutable || D->IsMutable;104Desc->InUnion = InUnion;105Desc->IsArrayElement = true;106Desc->IsVolatile = IsVolatile;107108if (auto Fn = D->ElemDesc->CtorFn)109Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,110Desc->InUnion || SD->isUnion(), D->ElemDesc);111}112}113114static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {115const unsigned NumElems = D->getNumElems();116const unsigned ElemSize =117D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);118119unsigned ElemOffset = 0;120for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {121auto *ElemPtr = Ptr + ElemOffset;122auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);123auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);124if (auto Fn = D->ElemDesc->DtorFn)125Fn(B, ElemLoc, D->ElemDesc);126}127}128129static void moveArrayDesc(Block *B, std::byte *Src, std::byte *Dst,130const Descriptor *D) {131const unsigned NumElems = D->getNumElems();132const unsigned ElemSize =133D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);134135unsigned ElemOffset = 0;136for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {137auto *SrcPtr = Src + ElemOffset;138auto *DstPtr = Dst + ElemOffset;139140auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);141auto *SrcElemLoc = reinterpret_cast<std::byte *>(SrcDesc + 1);142auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);143auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1);144145*DstDesc = *SrcDesc;146if (auto Fn = D->ElemDesc->MoveFn)147Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);148}149}150151static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,152bool IsVolatile, bool IsActive, bool IsUnionField,153bool InUnion, const Descriptor *D, unsigned FieldOffset) {154auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;155Desc->Offset = FieldOffset;156Desc->Desc = D;157Desc->IsInitialized = D->IsArray;158Desc->IsBase = false;159Desc->IsActive = IsActive && !IsUnionField;160Desc->InUnion = InUnion;161Desc->IsConst = IsConst || D->IsConst;162Desc->IsFieldMutable = IsMutable || D->IsMutable;163Desc->IsVolatile = IsVolatile || D->IsVolatile;164165if (auto Fn = D->CtorFn)166Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,167Desc->IsVolatile, Desc->IsActive, InUnion || D->isUnion(), D);168}169170static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,171bool IsVolatile, bool IsActive, bool InUnion,172const Descriptor *D, unsigned FieldOffset,173bool IsVirtualBase) {174assert(D);175assert(D->ElemRecord);176assert(!D->ElemRecord->isUnion()); // Unions cannot be base classes.177178auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;179Desc->Offset = FieldOffset;180Desc->Desc = D;181Desc->IsInitialized = D->IsArray;182Desc->IsBase = true;183Desc->IsVirtualBase = IsVirtualBase;184Desc->IsActive = IsActive && !InUnion;185Desc->IsConst = IsConst || D->IsConst;186Desc->IsFieldMutable = IsMutable || D->IsMutable;187Desc->InUnion = InUnion;188Desc->IsVolatile = false;189190for (const auto &V : D->ElemRecord->bases())191initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,192InUnion, V.Desc, V.Offset, false);193for (const auto &F : D->ElemRecord->fields())194initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,195InUnion, InUnion, F.Desc, F.Offset);196}197198static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,199bool IsVolatile, bool IsActive, bool InUnion,200const Descriptor *D) {201for (const auto &V : D->ElemRecord->bases())202initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,203V.Offset,204/*IsVirtualBase=*/false);205for (const auto &F : D->ElemRecord->fields()) {206bool IsUnionField = D->isUnion();207initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,208InUnion || IsUnionField, F.Desc, F.Offset);209}210for (const auto &V : D->ElemRecord->virtual_bases())211initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,212V.Offset,213/*IsVirtualBase=*/true);214}215216static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,217unsigned FieldOffset) {218if (auto Fn = D->DtorFn)219Fn(B, Ptr + FieldOffset, D);220}221222static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D,223unsigned FieldOffset) {224assert(D);225assert(D->ElemRecord);226227for (const auto &V : D->ElemRecord->bases())228destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset);229for (const auto &F : D->ElemRecord->fields())230destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset);231}232233static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {234for (const auto &F : D->ElemRecord->bases())235destroyBase(B, Ptr, F.Desc, F.Offset);236for (const auto &F : D->ElemRecord->fields())237destroyField(B, Ptr, F.Desc, F.Offset);238for (const auto &F : D->ElemRecord->virtual_bases())239destroyBase(B, Ptr, F.Desc, F.Offset);240}241242static void moveRecord(Block *B, std::byte *Src, std::byte *Dst,243const Descriptor *D) {244assert(D);245assert(D->ElemRecord);246247// FIXME: Code duplication.248for (const auto &F : D->ElemRecord->fields()) {249auto FieldOffset = F.Offset;250const auto *SrcDesc =251reinterpret_cast<const InlineDescriptor *>(Src + FieldOffset) - 1;252auto *DestDesc =253reinterpret_cast<InlineDescriptor *>(Dst + FieldOffset) - 1;254std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));255256if (auto Fn = F.Desc->MoveFn)257Fn(B, Src + FieldOffset, Dst + FieldOffset, F.Desc);258}259260for (const auto &Base : D->ElemRecord->bases()) {261auto BaseOffset = Base.Offset;262const auto *SrcDesc =263reinterpret_cast<const InlineDescriptor *>(Src + BaseOffset) - 1;264auto *DestDesc = reinterpret_cast<InlineDescriptor *>(Dst + BaseOffset) - 1;265std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));266267if (auto Fn = Base.Desc->MoveFn)268Fn(B, Src + BaseOffset, Dst + BaseOffset, Base.Desc);269}270271for (const auto &VBase : D->ElemRecord->virtual_bases()) {272auto VBaseOffset = VBase.Offset;273const auto *SrcDesc =274reinterpret_cast<const InlineDescriptor *>(Src + VBaseOffset) - 1;275auto *DestDesc =276reinterpret_cast<InlineDescriptor *>(Dst + VBaseOffset) - 1;277std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));278}279}280281static BlockCtorFn getCtorPrim(PrimType Type) {282// Floating types are special. They are primitives, but need their283// constructor called.284if (Type == PT_Float)285return ctorTy<PrimConv<PT_Float>::T>;286if (Type == PT_IntAP)287return ctorTy<PrimConv<PT_IntAP>::T>;288if (Type == PT_IntAPS)289return ctorTy<PrimConv<PT_IntAPS>::T>;290if (Type == PT_MemberPtr)291return ctorTy<PrimConv<PT_MemberPtr>::T>;292293COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);294}295296static BlockDtorFn getDtorPrim(PrimType Type) {297// Floating types are special. They are primitives, but need their298// destructor called, since they might allocate memory.299if (Type == PT_Float)300return dtorTy<PrimConv<PT_Float>::T>;301if (Type == PT_IntAP)302return dtorTy<PrimConv<PT_IntAP>::T>;303if (Type == PT_IntAPS)304return dtorTy<PrimConv<PT_IntAPS>::T>;305if (Type == PT_MemberPtr)306return dtorTy<PrimConv<PT_MemberPtr>::T>;307308COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);309}310311static BlockMoveFn getMovePrim(PrimType Type) {312if (Type == PT_Float)313return moveTy<PrimConv<PT_Float>::T>;314if (Type == PT_IntAP)315return moveTy<PrimConv<PT_IntAP>::T>;316if (Type == PT_IntAPS)317return moveTy<PrimConv<PT_IntAPS>::T>;318if (Type == PT_MemberPtr)319return moveTy<PrimConv<PT_MemberPtr>::T>;320COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);321}322323static BlockCtorFn getCtorArrayPrim(PrimType Type) {324TYPE_SWITCH(Type, return ctorArrayTy<T>);325llvm_unreachable("unknown Expr");326}327328static BlockDtorFn getDtorArrayPrim(PrimType Type) {329TYPE_SWITCH(Type, return dtorArrayTy<T>);330llvm_unreachable("unknown Expr");331}332333static BlockMoveFn getMoveArrayPrim(PrimType Type) {334TYPE_SWITCH(Type, return moveArrayTy<T>);335llvm_unreachable("unknown Expr");336}337338/// Primitives.339Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,340MetadataSize MD, bool IsConst, bool IsTemporary,341bool IsMutable, bool IsVolatile)342: Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),343MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),344IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),345IsVolatile(IsVolatile), CtorFn(getCtorPrim(Type)),346DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {347assert(AllocSize >= Size);348assert(Source && "Missing source");349}350351/// Primitive arrays.352Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,353size_t NumElems, bool IsConst, bool IsTemporary,354bool IsMutable)355: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),356MDSize(MD.value_or(0)),357AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),358IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),359IsArray(true), CtorFn(getCtorArrayPrim(Type)),360DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {361assert(Source && "Missing source");362assert(NumElems <= (MaxArrayElemBytes / ElemSize));363}364365/// Primitive unknown-size arrays.366Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,367bool IsTemporary, bool IsConst, UnknownSize)368: Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),369MDSize(MD.value_or(0)),370AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),371IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary),372IsArray(true), CtorFn(getCtorArrayPrim(Type)),373DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {374assert(Source && "Missing source");375}376377/// Arrays of composite elements.378Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy,379const Descriptor *Elem, MetadataSize MD,380unsigned NumElems, bool IsConst, bool IsTemporary,381bool IsMutable)382: Source(D), SourceType(SourceTy),383ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),384Size(ElemSize * NumElems), MDSize(MD.value_or(0)),385AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),386ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),387IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),388DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {389assert(Source && "Missing source");390}391392/// Unknown-size arrays of composite elements.393Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,394bool IsTemporary, UnknownSize)395: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),396Size(UnknownSizeMark), MDSize(MD.value_or(0)),397AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),398IsMutable(false), IsTemporary(IsTemporary), IsArray(true),399CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {400assert(Source && "Missing source");401}402403/// Composite records.404Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,405bool IsConst, bool IsTemporary, bool IsMutable,406bool IsVolatile)407: Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),408Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),409ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),410IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(ctorRecord),411DtorFn(dtorRecord), MoveFn(moveRecord) {412assert(Source && "Missing source");413}414415/// Dummy.416Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)417: Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)),418AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),419IsTemporary(false), IsDummy(true) {420assert(Source && "Missing source");421}422423QualType Descriptor::getType() const {424if (SourceType)425return QualType(SourceType, 0);426if (const auto *D = asValueDecl())427return D->getType();428if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))429return QualType(T->getTypeForDecl(), 0);430431// The Source sometimes has a different type than the once432// we really save. Try to consult the Record first.433if (isRecord())434return QualType(ElemRecord->getDecl()->getTypeForDecl(), 0);435if (const auto *E = asExpr())436return E->getType();437llvm_unreachable("Invalid descriptor type");438}439440QualType Descriptor::getElemQualType() const {441assert(isArray());442QualType T = getType();443if (T->isPointerOrReferenceType())444T = T->getPointeeType();445446if (const auto *AT = T->getAsArrayTypeUnsafe()) {447// For primitive arrays, we don't save a QualType at all,448// just a PrimType. Try to figure out the QualType here.449if (isPrimitiveArray()) {450while (T->isArrayType())451T = T->getAsArrayTypeUnsafe()->getElementType();452return T;453}454return AT->getElementType();455}456if (const auto *CT = T->getAs<ComplexType>())457return CT->getElementType();458if (const auto *CT = T->getAs<VectorType>())459return CT->getElementType();460461return T;462}463464QualType Descriptor::getDataType(const ASTContext &Ctx) const {465auto MakeArrayType = [&](QualType ElemType) -> QualType {466if (IsArray)467return Ctx.getConstantArrayType(468ElemType, APInt(64, static_cast<uint64_t>(getNumElems()), false),469nullptr, ArraySizeModifier::Normal, 0);470return ElemType;471};472473if (const auto *E = asExpr()) {474if (isa<CXXNewExpr>(E))475return MakeArrayType(E->getType()->getPointeeType());476477// std::allocator.allocate() call.478if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);479ME && ME->getRecordDecl()->getName() == "allocator" &&480ME->getMethodDecl()->getName() == "allocate")481return MakeArrayType(E->getType()->getPointeeType());482return E->getType();483}484485return getType();486}487488SourceLocation Descriptor::getLocation() const {489if (auto *D = dyn_cast<const Decl *>(Source))490return D->getLocation();491if (auto *E = dyn_cast<const Expr *>(Source))492return E->getExprLoc();493llvm_unreachable("Invalid descriptor type");494}495496SourceInfo Descriptor::getLoc() const {497if (const auto *D = dyn_cast<const Decl *>(Source))498return SourceInfo(D);499if (const auto *E = dyn_cast<const Expr *>(Source))500return SourceInfo(E);501llvm_unreachable("Invalid descriptor type");502}503504bool Descriptor::hasTrivialDtor() const {505if (isPrimitive() || isPrimitiveArray() || isDummy())506return true;507508if (isRecord()) {509assert(ElemRecord);510const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();511return !Dtor || Dtor->isTrivial();512}513514// Composite arrays.515assert(ElemDesc);516return ElemDesc->hasTrivialDtor();517}518519bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }520521InitMap::InitMap(unsigned N)522: UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {523std::fill_n(data(), numFields(N), 0);524}525526bool InitMap::initializeElement(unsigned I) {527unsigned Bucket = I / PER_FIELD;528T Mask = T(1) << (I % PER_FIELD);529if (!(data()[Bucket] & Mask)) {530data()[Bucket] |= Mask;531UninitFields -= 1;532}533return UninitFields == 0;534}535536bool InitMap::isElementInitialized(unsigned I) const {537unsigned Bucket = I / PER_FIELD;538return data()[Bucket] & (T(1) << (I % PER_FIELD));539}540541542