1*a7dea167SDimitry Andric //===--- Descriptor.cpp - Types for the constexpr VM ------------*- C++ -*-===// 2*a7dea167SDimitry Andric // 3*a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*a7dea167SDimitry Andric // 7*a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8*a7dea167SDimitry Andric 9*a7dea167SDimitry Andric #include "Descriptor.h" 10*a7dea167SDimitry Andric #include "Pointer.h" 11*a7dea167SDimitry Andric #include "PrimType.h" 12*a7dea167SDimitry Andric #include "Record.h" 13*a7dea167SDimitry Andric 14*a7dea167SDimitry Andric using namespace clang; 15*a7dea167SDimitry Andric using namespace clang::interp; 16*a7dea167SDimitry Andric 17*a7dea167SDimitry Andric template <typename T> 18*a7dea167SDimitry Andric static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *) { 19*a7dea167SDimitry Andric new (Ptr) T(); 20*a7dea167SDimitry Andric } 21*a7dea167SDimitry Andric 22*a7dea167SDimitry Andric template <typename T> static void dtorTy(Block *, char *Ptr, Descriptor *) { 23*a7dea167SDimitry Andric reinterpret_cast<T *>(Ptr)->~T(); 24*a7dea167SDimitry Andric } 25*a7dea167SDimitry Andric 26*a7dea167SDimitry Andric template <typename T> 27*a7dea167SDimitry Andric static void moveTy(Block *, char *Src, char *Dst, Descriptor *) { 28*a7dea167SDimitry Andric auto *SrcPtr = reinterpret_cast<T *>(Src); 29*a7dea167SDimitry Andric auto *DstPtr = reinterpret_cast<T *>(Dst); 30*a7dea167SDimitry Andric new (DstPtr) T(std::move(*SrcPtr)); 31*a7dea167SDimitry Andric } 32*a7dea167SDimitry Andric 33*a7dea167SDimitry Andric template <typename T> 34*a7dea167SDimitry Andric static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) { 35*a7dea167SDimitry Andric for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { 36*a7dea167SDimitry Andric new (&reinterpret_cast<T *>(Ptr)[I]) T(); 37*a7dea167SDimitry Andric } 38*a7dea167SDimitry Andric } 39*a7dea167SDimitry Andric 40*a7dea167SDimitry Andric template <typename T> 41*a7dea167SDimitry Andric static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) { 42*a7dea167SDimitry Andric for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { 43*a7dea167SDimitry Andric reinterpret_cast<T *>(Ptr)[I].~T(); 44*a7dea167SDimitry Andric } 45*a7dea167SDimitry Andric } 46*a7dea167SDimitry Andric 47*a7dea167SDimitry Andric template <typename T> 48*a7dea167SDimitry Andric static void moveArrayTy(Block *, char *Src, char *Dst, Descriptor *D) { 49*a7dea167SDimitry Andric for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { 50*a7dea167SDimitry Andric auto *SrcPtr = &reinterpret_cast<T *>(Src)[I]; 51*a7dea167SDimitry Andric auto *DstPtr = &reinterpret_cast<T *>(Dst)[I]; 52*a7dea167SDimitry Andric new (DstPtr) T(std::move(*SrcPtr)); 53*a7dea167SDimitry Andric } 54*a7dea167SDimitry Andric } 55*a7dea167SDimitry Andric 56*a7dea167SDimitry Andric static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable, 57*a7dea167SDimitry Andric bool IsActive, Descriptor *D) { 58*a7dea167SDimitry Andric const unsigned NumElems = D->getNumElems(); 59*a7dea167SDimitry Andric const unsigned ElemSize = 60*a7dea167SDimitry Andric D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); 61*a7dea167SDimitry Andric 62*a7dea167SDimitry Andric unsigned ElemOffset = 0; 63*a7dea167SDimitry Andric for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { 64*a7dea167SDimitry Andric auto *ElemPtr = Ptr + ElemOffset; 65*a7dea167SDimitry Andric auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr); 66*a7dea167SDimitry Andric auto *ElemLoc = reinterpret_cast<char *>(Desc + 1); 67*a7dea167SDimitry Andric auto *SD = D->ElemDesc; 68*a7dea167SDimitry Andric 69*a7dea167SDimitry Andric Desc->Offset = ElemOffset + sizeof(InlineDescriptor); 70*a7dea167SDimitry Andric Desc->Desc = SD; 71*a7dea167SDimitry Andric Desc->IsInitialized = true; 72*a7dea167SDimitry Andric Desc->IsBase = false; 73*a7dea167SDimitry Andric Desc->IsActive = IsActive; 74*a7dea167SDimitry Andric Desc->IsConst = IsConst || D->IsConst; 75*a7dea167SDimitry Andric Desc->IsMutable = IsMutable || D->IsMutable; 76*a7dea167SDimitry Andric if (auto Fn = D->ElemDesc->CtorFn) 77*a7dea167SDimitry Andric Fn(B, ElemLoc, Desc->IsConst, Desc->IsMutable, IsActive, D->ElemDesc); 78*a7dea167SDimitry Andric } 79*a7dea167SDimitry Andric } 80*a7dea167SDimitry Andric 81*a7dea167SDimitry Andric static void dtorArrayDesc(Block *B, char *Ptr, Descriptor *D) { 82*a7dea167SDimitry Andric const unsigned NumElems = D->getNumElems(); 83*a7dea167SDimitry Andric const unsigned ElemSize = 84*a7dea167SDimitry Andric D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); 85*a7dea167SDimitry Andric 86*a7dea167SDimitry Andric unsigned ElemOffset = 0; 87*a7dea167SDimitry Andric for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { 88*a7dea167SDimitry Andric auto *ElemPtr = Ptr + ElemOffset; 89*a7dea167SDimitry Andric auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr); 90*a7dea167SDimitry Andric auto *ElemLoc = reinterpret_cast<char *>(Desc + 1); 91*a7dea167SDimitry Andric if (auto Fn = D->ElemDesc->DtorFn) 92*a7dea167SDimitry Andric Fn(B, ElemLoc, D->ElemDesc); 93*a7dea167SDimitry Andric } 94*a7dea167SDimitry Andric } 95*a7dea167SDimitry Andric 96*a7dea167SDimitry Andric static void moveArrayDesc(Block *B, char *Src, char *Dst, Descriptor *D) { 97*a7dea167SDimitry Andric const unsigned NumElems = D->getNumElems(); 98*a7dea167SDimitry Andric const unsigned ElemSize = 99*a7dea167SDimitry Andric D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); 100*a7dea167SDimitry Andric 101*a7dea167SDimitry Andric unsigned ElemOffset = 0; 102*a7dea167SDimitry Andric for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { 103*a7dea167SDimitry Andric auto *SrcPtr = Src + ElemOffset; 104*a7dea167SDimitry Andric auto *DstPtr = Dst + ElemOffset; 105*a7dea167SDimitry Andric 106*a7dea167SDimitry Andric auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr); 107*a7dea167SDimitry Andric auto *SrcElemLoc = reinterpret_cast<char *>(SrcDesc + 1); 108*a7dea167SDimitry Andric auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr); 109*a7dea167SDimitry Andric auto *DstElemLoc = reinterpret_cast<char *>(DstDesc + 1); 110*a7dea167SDimitry Andric 111*a7dea167SDimitry Andric *DstDesc = *SrcDesc; 112*a7dea167SDimitry Andric if (auto Fn = D->ElemDesc->MoveFn) 113*a7dea167SDimitry Andric Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc); 114*a7dea167SDimitry Andric } 115*a7dea167SDimitry Andric } 116*a7dea167SDimitry Andric 117*a7dea167SDimitry Andric static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable, 118*a7dea167SDimitry Andric bool IsActive, Descriptor *D) { 119*a7dea167SDimitry Andric const bool IsUnion = D->ElemRecord->isUnion(); 120*a7dea167SDimitry Andric auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) { 121*a7dea167SDimitry Andric auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1; 122*a7dea167SDimitry Andric Desc->Offset = SubOff; 123*a7dea167SDimitry Andric Desc->Desc = F; 124*a7dea167SDimitry Andric Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase; 125*a7dea167SDimitry Andric Desc->IsBase = IsBase; 126*a7dea167SDimitry Andric Desc->IsActive = IsActive && !IsUnion; 127*a7dea167SDimitry Andric Desc->IsConst = IsConst || F->IsConst; 128*a7dea167SDimitry Andric Desc->IsMutable = IsMutable || F->IsMutable; 129*a7dea167SDimitry Andric if (auto Fn = F->CtorFn) 130*a7dea167SDimitry Andric Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsMutable, Desc->IsActive, F); 131*a7dea167SDimitry Andric }; 132*a7dea167SDimitry Andric for (const auto &B : D->ElemRecord->bases()) 133*a7dea167SDimitry Andric CtorSub(B.Offset, B.Desc, /*isBase=*/true); 134*a7dea167SDimitry Andric for (const auto &F : D->ElemRecord->fields()) 135*a7dea167SDimitry Andric CtorSub(F.Offset, F.Desc, /*isBase=*/false); 136*a7dea167SDimitry Andric for (const auto &V : D->ElemRecord->virtual_bases()) 137*a7dea167SDimitry Andric CtorSub(V.Offset, V.Desc, /*isBase=*/true); 138*a7dea167SDimitry Andric } 139*a7dea167SDimitry Andric 140*a7dea167SDimitry Andric static void dtorRecord(Block *B, char *Ptr, Descriptor *D) { 141*a7dea167SDimitry Andric auto DtorSub = [=](unsigned SubOff, Descriptor *F) { 142*a7dea167SDimitry Andric if (auto Fn = F->DtorFn) 143*a7dea167SDimitry Andric Fn(B, Ptr + SubOff, F); 144*a7dea167SDimitry Andric }; 145*a7dea167SDimitry Andric for (const auto &F : D->ElemRecord->bases()) 146*a7dea167SDimitry Andric DtorSub(F.Offset, F.Desc); 147*a7dea167SDimitry Andric for (const auto &F : D->ElemRecord->fields()) 148*a7dea167SDimitry Andric DtorSub(F.Offset, F.Desc); 149*a7dea167SDimitry Andric for (const auto &F : D->ElemRecord->virtual_bases()) 150*a7dea167SDimitry Andric DtorSub(F.Offset, F.Desc); 151*a7dea167SDimitry Andric } 152*a7dea167SDimitry Andric 153*a7dea167SDimitry Andric static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D) { 154*a7dea167SDimitry Andric for (const auto &F : D->ElemRecord->fields()) { 155*a7dea167SDimitry Andric auto FieldOff = F.Offset; 156*a7dea167SDimitry Andric auto FieldDesc = F.Desc; 157*a7dea167SDimitry Andric 158*a7dea167SDimitry Andric *(reinterpret_cast<Descriptor **>(Dst + FieldOff) - 1) = FieldDesc; 159*a7dea167SDimitry Andric if (auto Fn = FieldDesc->MoveFn) 160*a7dea167SDimitry Andric Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc); 161*a7dea167SDimitry Andric } 162*a7dea167SDimitry Andric } 163*a7dea167SDimitry Andric 164*a7dea167SDimitry Andric static BlockCtorFn getCtorPrim(PrimType Type) { 165*a7dea167SDimitry Andric COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr); 166*a7dea167SDimitry Andric } 167*a7dea167SDimitry Andric 168*a7dea167SDimitry Andric static BlockDtorFn getDtorPrim(PrimType Type) { 169*a7dea167SDimitry Andric COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr); 170*a7dea167SDimitry Andric } 171*a7dea167SDimitry Andric 172*a7dea167SDimitry Andric static BlockMoveFn getMovePrim(PrimType Type) { 173*a7dea167SDimitry Andric COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr); 174*a7dea167SDimitry Andric } 175*a7dea167SDimitry Andric 176*a7dea167SDimitry Andric static BlockCtorFn getCtorArrayPrim(PrimType Type) { 177*a7dea167SDimitry Andric COMPOSITE_TYPE_SWITCH(Type, return ctorArrayTy<T>, return nullptr); 178*a7dea167SDimitry Andric } 179*a7dea167SDimitry Andric 180*a7dea167SDimitry Andric static BlockDtorFn getDtorArrayPrim(PrimType Type) { 181*a7dea167SDimitry Andric COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr); 182*a7dea167SDimitry Andric } 183*a7dea167SDimitry Andric 184*a7dea167SDimitry Andric static BlockMoveFn getMoveArrayPrim(PrimType Type) { 185*a7dea167SDimitry Andric COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr); 186*a7dea167SDimitry Andric } 187*a7dea167SDimitry Andric 188*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsConst, 189*a7dea167SDimitry Andric bool IsTemporary, bool IsMutable) 190*a7dea167SDimitry Andric : Source(D), ElemSize(primSize(Type)), Size(ElemSize), AllocSize(Size), 191*a7dea167SDimitry Andric IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), 192*a7dea167SDimitry Andric CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)), 193*a7dea167SDimitry Andric MoveFn(getMovePrim(Type)) { 194*a7dea167SDimitry Andric assert(Source && "Missing source"); 195*a7dea167SDimitry Andric } 196*a7dea167SDimitry Andric 197*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems, 198*a7dea167SDimitry Andric bool IsConst, bool IsTemporary, bool IsMutable) 199*a7dea167SDimitry Andric : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems), 200*a7dea167SDimitry Andric AllocSize(align(Size) + sizeof(InitMap *)), IsConst(IsConst), 201*a7dea167SDimitry Andric IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true), 202*a7dea167SDimitry Andric CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)), 203*a7dea167SDimitry Andric MoveFn(getMoveArrayPrim(Type)) { 204*a7dea167SDimitry Andric assert(Source && "Missing source"); 205*a7dea167SDimitry Andric } 206*a7dea167SDimitry Andric 207*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary, 208*a7dea167SDimitry Andric UnknownSize) 209*a7dea167SDimitry Andric : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), 210*a7dea167SDimitry Andric AllocSize(alignof(void *)), IsConst(true), IsMutable(false), 211*a7dea167SDimitry Andric IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)), 212*a7dea167SDimitry Andric DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) { 213*a7dea167SDimitry Andric assert(Source && "Missing source"); 214*a7dea167SDimitry Andric } 215*a7dea167SDimitry Andric 216*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems, 217*a7dea167SDimitry Andric bool IsConst, bool IsTemporary, bool IsMutable) 218*a7dea167SDimitry Andric : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)), 219*a7dea167SDimitry Andric Size(ElemSize * NumElems), 220*a7dea167SDimitry Andric AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem), 221*a7dea167SDimitry Andric IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), 222*a7dea167SDimitry Andric IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), 223*a7dea167SDimitry Andric MoveFn(moveArrayDesc) { 224*a7dea167SDimitry Andric assert(Source && "Missing source"); 225*a7dea167SDimitry Andric } 226*a7dea167SDimitry Andric 227*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, 228*a7dea167SDimitry Andric UnknownSize) 229*a7dea167SDimitry Andric : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)), 230*a7dea167SDimitry Andric Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem), 231*a7dea167SDimitry Andric IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true), 232*a7dea167SDimitry Andric CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) { 233*a7dea167SDimitry Andric assert(Source && "Missing source"); 234*a7dea167SDimitry Andric } 235*a7dea167SDimitry Andric 236*a7dea167SDimitry Andric Descriptor::Descriptor(const DeclTy &D, Record *R, bool IsConst, 237*a7dea167SDimitry Andric bool IsTemporary, bool IsMutable) 238*a7dea167SDimitry Andric : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())), 239*a7dea167SDimitry Andric Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst), 240*a7dea167SDimitry Andric IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(ctorRecord), 241*a7dea167SDimitry Andric DtorFn(dtorRecord), MoveFn(moveRecord) { 242*a7dea167SDimitry Andric assert(Source && "Missing source"); 243*a7dea167SDimitry Andric } 244*a7dea167SDimitry Andric 245*a7dea167SDimitry Andric QualType Descriptor::getType() const { 246*a7dea167SDimitry Andric if (auto *E = asExpr()) 247*a7dea167SDimitry Andric return E->getType(); 248*a7dea167SDimitry Andric if (auto *D = asValueDecl()) 249*a7dea167SDimitry Andric return D->getType(); 250*a7dea167SDimitry Andric llvm_unreachable("Invalid descriptor type"); 251*a7dea167SDimitry Andric } 252*a7dea167SDimitry Andric 253*a7dea167SDimitry Andric SourceLocation Descriptor::getLocation() const { 254*a7dea167SDimitry Andric if (auto *D = Source.dyn_cast<const Decl *>()) 255*a7dea167SDimitry Andric return D->getLocation(); 256*a7dea167SDimitry Andric if (auto *E = Source.dyn_cast<const Expr *>()) 257*a7dea167SDimitry Andric return E->getExprLoc(); 258*a7dea167SDimitry Andric llvm_unreachable("Invalid descriptor type"); 259*a7dea167SDimitry Andric } 260*a7dea167SDimitry Andric 261*a7dea167SDimitry Andric InitMap::InitMap(unsigned N) : UninitFields(N) { 262*a7dea167SDimitry Andric for (unsigned I = 0; I < N / PER_FIELD; ++I) { 263*a7dea167SDimitry Andric data()[I] = 0; 264*a7dea167SDimitry Andric } 265*a7dea167SDimitry Andric } 266*a7dea167SDimitry Andric 267*a7dea167SDimitry Andric InitMap::T *InitMap::data() { 268*a7dea167SDimitry Andric auto *Start = reinterpret_cast<char *>(this) + align(sizeof(InitMap)); 269*a7dea167SDimitry Andric return reinterpret_cast<T *>(Start); 270*a7dea167SDimitry Andric } 271*a7dea167SDimitry Andric 272*a7dea167SDimitry Andric bool InitMap::initialize(unsigned I) { 273*a7dea167SDimitry Andric unsigned Bucket = I / PER_FIELD; 274*a7dea167SDimitry Andric unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD); 275*a7dea167SDimitry Andric if (!(data()[Bucket] & Mask)) { 276*a7dea167SDimitry Andric data()[Bucket] |= Mask; 277*a7dea167SDimitry Andric UninitFields -= 1; 278*a7dea167SDimitry Andric } 279*a7dea167SDimitry Andric return UninitFields == 0; 280*a7dea167SDimitry Andric } 281*a7dea167SDimitry Andric 282*a7dea167SDimitry Andric bool InitMap::isInitialized(unsigned I) { 283*a7dea167SDimitry Andric unsigned Bucket = I / PER_FIELD; 284*a7dea167SDimitry Andric unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD); 285*a7dea167SDimitry Andric return data()[Bucket] & Mask; 286*a7dea167SDimitry Andric } 287*a7dea167SDimitry Andric 288*a7dea167SDimitry Andric InitMap *InitMap::allocate(unsigned N) { 289*a7dea167SDimitry Andric const size_t NumFields = ((N + PER_FIELD - 1) / PER_FIELD); 290*a7dea167SDimitry Andric const size_t Size = align(sizeof(InitMap)) + NumFields * PER_FIELD; 291*a7dea167SDimitry Andric return new (malloc(Size)) InitMap(N); 292*a7dea167SDimitry Andric } 293