Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp
35291 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 "Floating.h"11#include "FunctionPointer.h"12#include "IntegralAP.h"13#include "MemberPointer.h"14#include "Pointer.h"15#include "PrimType.h"16#include "Record.h"1718using namespace clang;19using namespace clang::interp;2021template <typename T>22static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool,23const Descriptor *) {24new (Ptr) T();25}2627template <typename T>28static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {29reinterpret_cast<T *>(Ptr)->~T();30}3132template <typename T>33static void moveTy(Block *, const std::byte *Src, std::byte *Dst,34const Descriptor *) {35const auto *SrcPtr = reinterpret_cast<const T *>(Src);36auto *DstPtr = reinterpret_cast<T *>(Dst);37new (DstPtr) T(std::move(*SrcPtr));38}3940template <typename T>41static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool,42const Descriptor *D) {43new (Ptr) InitMapPtr(std::nullopt);4445Ptr += sizeof(InitMapPtr);46for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {47new (&reinterpret_cast<T *>(Ptr)[I]) T();48}49}5051template <typename T>52static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {53InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);5455if (IMP)56IMP = std::nullopt;57Ptr += sizeof(InitMapPtr);58for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {59reinterpret_cast<T *>(Ptr)[I].~T();60}61}6263template <typename T>64static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst,65const Descriptor *D) {66// FIXME: Get rid of the const_cast.67InitMapPtr &SrcIMP =68*reinterpret_cast<InitMapPtr *>(const_cast<std::byte *>(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) {77const auto *SrcPtr = &reinterpret_cast<const 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 IsActive, const Descriptor *D) {85const unsigned NumElems = D->getNumElems();86const unsigned ElemSize =87D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);8889unsigned ElemOffset = 0;90for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {91auto *ElemPtr = Ptr + ElemOffset;92auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);93auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);94auto *SD = D->ElemDesc;9596Desc->Offset = ElemOffset + sizeof(InlineDescriptor);97Desc->Desc = SD;98Desc->IsInitialized = true;99Desc->IsBase = false;100Desc->IsActive = IsActive;101Desc->IsConst = IsConst || D->IsConst;102Desc->IsFieldMutable = IsMutable || D->IsMutable;103if (auto Fn = D->ElemDesc->CtorFn)104Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsActive,105D->ElemDesc);106}107}108109static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {110const unsigned NumElems = D->getNumElems();111const unsigned ElemSize =112D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);113114unsigned ElemOffset = 0;115for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {116auto *ElemPtr = Ptr + ElemOffset;117auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);118auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);119if (auto Fn = D->ElemDesc->DtorFn)120Fn(B, ElemLoc, D->ElemDesc);121}122}123124static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst,125const Descriptor *D) {126const unsigned NumElems = D->getNumElems();127const unsigned ElemSize =128D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);129130unsigned ElemOffset = 0;131for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {132const auto *SrcPtr = Src + ElemOffset;133auto *DstPtr = Dst + ElemOffset;134135const auto *SrcDesc = reinterpret_cast<const InlineDescriptor *>(SrcPtr);136const auto *SrcElemLoc = reinterpret_cast<const std::byte *>(SrcDesc + 1);137auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);138auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1);139140*DstDesc = *SrcDesc;141if (auto Fn = D->ElemDesc->MoveFn)142Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);143}144}145146static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,147bool IsActive, bool IsUnion, const Descriptor *D,148unsigned FieldOffset) {149auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;150Desc->Offset = FieldOffset;151Desc->Desc = D;152Desc->IsInitialized = D->IsArray;153Desc->IsBase = false;154Desc->IsActive = IsActive && !IsUnion;155Desc->IsConst = IsConst || D->IsConst;156Desc->IsFieldMutable = IsMutable || D->IsMutable;157158if (auto Fn = D->CtorFn)159Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,160Desc->IsActive, D);161}162163static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,164bool IsActive, const Descriptor *D, unsigned FieldOffset,165bool IsVirtualBase) {166assert(D);167assert(D->ElemRecord);168169bool IsUnion = D->ElemRecord->isUnion();170auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;171Desc->Offset = FieldOffset;172Desc->Desc = D;173Desc->IsInitialized = D->IsArray;174Desc->IsBase = true;175Desc->IsVirtualBase = IsVirtualBase;176Desc->IsActive = IsActive && !IsUnion;177Desc->IsConst = IsConst || D->IsConst;178Desc->IsFieldMutable = IsMutable || D->IsMutable;179180for (const auto &V : D->ElemRecord->bases())181initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,182V.Offset, false);183for (const auto &F : D->ElemRecord->fields())184initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion,185F.Desc, F.Offset);186}187188static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,189bool IsActive, const Descriptor *D) {190for (const auto &V : D->ElemRecord->bases())191initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false);192for (const auto &F : D->ElemRecord->fields())193initField(B, Ptr, IsConst, IsMutable, IsActive, D->ElemRecord->isUnion(), F.Desc, F.Offset);194for (const auto &V : D->ElemRecord->virtual_bases())195initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true);196}197198static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,199unsigned FieldOffset) {200if (auto Fn = D->DtorFn)201Fn(B, Ptr + FieldOffset, D);202}203204static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D,205unsigned FieldOffset) {206assert(D);207assert(D->ElemRecord);208209for (const auto &V : D->ElemRecord->bases())210destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset);211for (const auto &F : D->ElemRecord->fields())212destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset);213}214215static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {216for (const auto &F : D->ElemRecord->bases())217destroyBase(B, Ptr, F.Desc, F.Offset);218for (const auto &F : D->ElemRecord->fields())219destroyField(B, Ptr, F.Desc, F.Offset);220for (const auto &F : D->ElemRecord->virtual_bases())221destroyBase(B, Ptr, F.Desc, F.Offset);222}223224static void moveRecord(Block *B, const std::byte *Src, std::byte *Dst,225const Descriptor *D) {226for (const auto &F : D->ElemRecord->fields()) {227auto FieldOff = F.Offset;228auto *FieldDesc = F.Desc;229230if (auto Fn = FieldDesc->MoveFn)231Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc);232}233}234235static BlockCtorFn getCtorPrim(PrimType Type) {236// Floating types are special. They are primitives, but need their237// constructor called.238if (Type == PT_Float)239return ctorTy<PrimConv<PT_Float>::T>;240if (Type == PT_IntAP)241return ctorTy<PrimConv<PT_IntAP>::T>;242if (Type == PT_IntAPS)243return ctorTy<PrimConv<PT_IntAPS>::T>;244if (Type == PT_MemberPtr)245return ctorTy<PrimConv<PT_MemberPtr>::T>;246247COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);248}249250static BlockDtorFn getDtorPrim(PrimType Type) {251// Floating types are special. They are primitives, but need their252// destructor called, since they might allocate memory.253if (Type == PT_Float)254return dtorTy<PrimConv<PT_Float>::T>;255if (Type == PT_IntAP)256return dtorTy<PrimConv<PT_IntAP>::T>;257if (Type == PT_IntAPS)258return dtorTy<PrimConv<PT_IntAPS>::T>;259if (Type == PT_MemberPtr)260return dtorTy<PrimConv<PT_MemberPtr>::T>;261262COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);263}264265static BlockMoveFn getMovePrim(PrimType Type) {266COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);267}268269static BlockCtorFn getCtorArrayPrim(PrimType Type) {270TYPE_SWITCH(Type, return ctorArrayTy<T>);271llvm_unreachable("unknown Expr");272}273274static BlockDtorFn getDtorArrayPrim(PrimType Type) {275TYPE_SWITCH(Type, return dtorArrayTy<T>);276llvm_unreachable("unknown Expr");277}278279static BlockMoveFn getMoveArrayPrim(PrimType Type) {280TYPE_SWITCH(Type, return moveArrayTy<T>);281llvm_unreachable("unknown Expr");282}283284/// Primitives.285Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,286bool IsConst, bool IsTemporary, bool IsMutable)287: Source(D), ElemSize(primSize(Type)), Size(ElemSize),288MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),289IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),290CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),291MoveFn(getMovePrim(Type)) {292assert(AllocSize >= Size);293assert(Source && "Missing source");294}295296/// Primitive arrays.297Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,298size_t NumElems, bool IsConst, bool IsTemporary,299bool IsMutable)300: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),301MDSize(MD.value_or(0)),302AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),303IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),304IsArray(true), CtorFn(getCtorArrayPrim(Type)),305DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {306assert(Source && "Missing source");307assert(NumElems <= (MaxArrayElemBytes / ElemSize));308}309310/// Primitive unknown-size arrays.311Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,312bool IsTemporary, UnknownSize)313: Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),314MDSize(MD.value_or(0)),315AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), IsConst(true),316IsMutable(false), IsTemporary(IsTemporary), IsArray(true),317CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),318MoveFn(getMoveArrayPrim(Type)) {319assert(Source && "Missing source");320}321322/// Arrays of composite elements.323Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,324unsigned NumElems, bool IsConst, bool IsTemporary,325bool IsMutable)326: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),327Size(ElemSize * NumElems), MDSize(MD.value_or(0)),328AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),329ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),330IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),331DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {332assert(Source && "Missing source");333}334335/// Unknown-size arrays of composite elements.336Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,337bool IsTemporary, UnknownSize)338: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),339Size(UnknownSizeMark), MDSize(MD.value_or(0)),340AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),341IsMutable(false), IsTemporary(IsTemporary), IsArray(true),342CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {343assert(Source && "Missing source");344}345346/// Composite records.347Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,348bool IsConst, bool IsTemporary, bool IsMutable)349: Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),350Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),351ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),352IsTemporary(IsTemporary), CtorFn(ctorRecord), DtorFn(dtorRecord),353MoveFn(moveRecord) {354assert(Source && "Missing source");355}356357/// Dummy.358Descriptor::Descriptor(const DeclTy &D)359: Source(D), ElemSize(1), Size(1), MDSize(0), AllocSize(MDSize),360ElemRecord(nullptr), IsConst(true), IsMutable(false), IsTemporary(false),361IsDummy(true) {362assert(Source && "Missing source");363}364365QualType Descriptor::getType() const {366if (const auto *E = asExpr())367return E->getType();368if (const auto *D = asValueDecl())369return D->getType();370if (const auto *T = dyn_cast<TypeDecl>(asDecl()))371return QualType(T->getTypeForDecl(), 0);372llvm_unreachable("Invalid descriptor type");373}374375QualType Descriptor::getElemQualType() const {376assert(isArray());377QualType T = getType();378if (const auto *AT = T->getAsArrayTypeUnsafe())379return AT->getElementType();380if (const auto *CT = T->getAs<ComplexType>())381return CT->getElementType();382if (const auto *CT = T->getAs<VectorType>())383return CT->getElementType();384llvm_unreachable("Array that's not an array/complex/vector type?");385}386387SourceLocation Descriptor::getLocation() const {388if (auto *D = Source.dyn_cast<const Decl *>())389return D->getLocation();390if (auto *E = Source.dyn_cast<const Expr *>())391return E->getExprLoc();392llvm_unreachable("Invalid descriptor type");393}394395InitMap::InitMap(unsigned N)396: UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {397std::fill_n(data(), numFields(N), 0);398}399400bool InitMap::initializeElement(unsigned I) {401unsigned Bucket = I / PER_FIELD;402T Mask = T(1) << (I % PER_FIELD);403if (!(data()[Bucket] & Mask)) {404data()[Bucket] |= Mask;405UninitFields -= 1;406}407return UninitFields == 0;408}409410bool InitMap::isElementInitialized(unsigned I) const {411unsigned Bucket = I / PER_FIELD;412return data()[Bucket] & (T(1) << (I % PER_FIELD));413}414415416