brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.5 KiB · 0a81959 Raw
488 lines · cpp
1//===--- Descriptor.cpp - Types for the constexpr VM ------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Descriptor.h"10#include "Boolean.h"11#include "FixedPoint.h"12#include "Floating.h"13#include "IntegralAP.h"14#include "MemberPointer.h"15#include "Pointer.h"16#include "PrimType.h"17#include "Record.h"18#include "Source.h"19#include "clang/AST/ExprCXX.h"20 21using namespace clang;22using namespace clang::interp;23 24template <typename T> static constexpr bool needsCtor() {25  if constexpr (std::is_same_v<T, Integral<8, true>> ||26                std::is_same_v<T, Integral<8, false>> ||27                std::is_same_v<T, Integral<16, true>> ||28                std::is_same_v<T, Integral<16, false>> ||29                std::is_same_v<T, Integral<32, true>> ||30                std::is_same_v<T, Integral<32, false>> ||31                std::is_same_v<T, Integral<64, true>> ||32                std::is_same_v<T, Integral<64, false>> ||33                std::is_same_v<T, Boolean>)34    return false;35 36  return true;37}38 39template <typename T>40static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,41                   const Descriptor *) {42  static_assert(needsCtor<T>());43  new (Ptr) T();44}45 46template <typename T>47static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {48  static_assert(needsCtor<T>());49  reinterpret_cast<T *>(Ptr)->~T();50}51 52template <typename T>53static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,54                        const Descriptor *D) {55  new (Ptr) InitMapPtr(std::nullopt);56 57  if constexpr (needsCtor<T>()) {58    Ptr += sizeof(InitMapPtr);59    for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {60      new (&reinterpret_cast<T *>(Ptr)[I]) T();61    }62  }63}64 65template <typename T>66static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {67  InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);68 69  if (IMP)70    IMP = std::nullopt;71 72  if constexpr (needsCtor<T>()) {73    Ptr += sizeof(InitMapPtr);74    for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {75      reinterpret_cast<T *>(Ptr)[I].~T();76    }77  }78}79 80static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,81                          bool IsMutable, bool IsVolatile, bool IsActive,82                          bool InUnion, const Descriptor *D) {83  const unsigned NumElems = D->getNumElems();84  const unsigned ElemSize =85      D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);86 87  unsigned ElemOffset = 0;88  for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {89    auto *ElemPtr = Ptr + ElemOffset;90    auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);91    auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);92    auto *SD = D->ElemDesc;93 94    Desc->Offset = ElemOffset + sizeof(InlineDescriptor);95    Desc->Desc = SD;96    Desc->IsInitialized = true;97    Desc->IsBase = false;98    Desc->IsActive = IsActive;99    Desc->IsConst = IsConst || D->IsConst;100    Desc->IsFieldMutable = IsMutable || D->IsMutable;101    Desc->InUnion = InUnion;102    Desc->IsArrayElement = true;103    Desc->IsVolatile = IsVolatile;104 105    if (auto Fn = D->ElemDesc->CtorFn)106      Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,107         Desc->InUnion || SD->isUnion(), D->ElemDesc);108  }109}110 111static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {112  const unsigned NumElems = D->getNumElems();113  const unsigned ElemSize =114      D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);115 116  unsigned ElemOffset = 0;117  auto Dtor = D->ElemDesc->DtorFn;118  assert(Dtor &&119         "a composite array without an elem dtor shouldn't have a dtor itself");120  for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {121    auto *ElemPtr = Ptr + ElemOffset;122    auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);123    auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);124    Dtor(B, ElemLoc, D->ElemDesc);125  }126}127 128static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,129                      bool IsVolatile, bool IsActive, bool IsUnionField,130                      bool InUnion, const Descriptor *D, unsigned FieldOffset) {131  auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;132  Desc->Offset = FieldOffset;133  Desc->Desc = D;134  Desc->IsInitialized = D->IsArray;135  Desc->IsBase = false;136  Desc->IsActive = IsActive && !IsUnionField;137  Desc->InUnion = InUnion;138  Desc->IsConst = IsConst || D->IsConst;139  Desc->IsFieldMutable = IsMutable || D->IsMutable;140  Desc->IsVolatile = IsVolatile || D->IsVolatile;141  // True if this field is const AND the parent is mutable.142  Desc->IsConstInMutable = Desc->IsConst && IsMutable;143 144  if (auto Fn = D->CtorFn)145    Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,146       Desc->IsVolatile, Desc->IsActive, InUnion || D->isUnion(), D);147}148 149static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,150                     bool IsVolatile, bool IsActive, bool InUnion,151                     const Descriptor *D, unsigned FieldOffset,152                     bool IsVirtualBase) {153  assert(D);154  assert(D->ElemRecord);155  assert(!D->ElemRecord->isUnion()); // Unions cannot be base classes.156 157  auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;158  Desc->Offset = FieldOffset;159  Desc->Desc = D;160  Desc->IsInitialized = D->IsArray;161  Desc->IsBase = true;162  Desc->IsVirtualBase = IsVirtualBase;163  Desc->IsActive = IsActive && !InUnion;164  Desc->IsConst = IsConst || D->IsConst;165  Desc->IsFieldMutable = IsMutable || D->IsMutable;166  Desc->InUnion = InUnion;167  Desc->IsVolatile = false;168 169  for (const auto &V : D->ElemRecord->bases())170    initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,171             InUnion, V.Desc, V.Offset, false);172  for (const auto &F : D->ElemRecord->fields())173    initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,174              InUnion, InUnion, F.Desc, F.Offset);175}176 177static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,178                       bool IsVolatile, bool IsActive, bool InUnion,179                       const Descriptor *D) {180  for (const auto &V : D->ElemRecord->bases())181    initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,182             V.Offset,183             /*IsVirtualBase=*/false);184  for (const auto &F : D->ElemRecord->fields()) {185    bool IsUnionField = D->isUnion();186    initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,187              InUnion || IsUnionField, F.Desc, F.Offset);188  }189  for (const auto &V : D->ElemRecord->virtual_bases())190    initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,191             V.Offset,192             /*IsVirtualBase=*/true);193}194 195static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,196                         unsigned FieldOffset) {197  if (auto Fn = D->DtorFn)198    Fn(B, Ptr + FieldOffset, D);199}200 201static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D,202                        unsigned FieldOffset) {203  assert(D);204  assert(D->ElemRecord);205 206  for (const auto &V : D->ElemRecord->bases())207    destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset);208  for (const auto &F : D->ElemRecord->fields())209    destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset);210}211 212static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {213  for (const auto &F : D->ElemRecord->bases())214    destroyBase(B, Ptr, F.Desc, F.Offset);215  for (const auto &F : D->ElemRecord->fields())216    destroyField(B, Ptr, F.Desc, F.Offset);217  for (const auto &F : D->ElemRecord->virtual_bases())218    destroyBase(B, Ptr, F.Desc, F.Offset);219}220 221/// Whether a record needs its descriptor dtor function called.222static bool needsRecordDtor(const Record *R) {223  for (const auto &B : R->bases()) {224    if (B.Desc->DtorFn)225      return true;226  }227 228  for (const auto &F : R->fields()) {229    if (F.Desc->DtorFn)230      return true;231  }232 233  for (const auto &V : R->virtual_bases()) {234    if (V.Desc->DtorFn)235      return true;236  }237  return false;238}239 240static BlockCtorFn getCtorPrim(PrimType T) {241  switch (T) {242  case PT_Float:243    return ctorTy<PrimConv<PT_Float>::T>;244  case PT_IntAP:245    return ctorTy<PrimConv<PT_IntAP>::T>;246  case PT_IntAPS:247    return ctorTy<PrimConv<PT_IntAPS>::T>;248  case PT_Ptr:249    return ctorTy<PrimConv<PT_Ptr>::T>;250  case PT_MemberPtr:251    return ctorTy<PrimConv<PT_MemberPtr>::T>;252  default:253    return nullptr;254  }255  llvm_unreachable("Unhandled PrimType");256}257 258static BlockDtorFn getDtorPrim(PrimType T) {259  switch (T) {260  case PT_Float:261    return dtorTy<PrimConv<PT_Float>::T>;262  case PT_IntAP:263    return dtorTy<PrimConv<PT_IntAP>::T>;264  case PT_IntAPS:265    return dtorTy<PrimConv<PT_IntAPS>::T>;266  case PT_Ptr:267    return dtorTy<PrimConv<PT_Ptr>::T>;268  case PT_MemberPtr:269    return dtorTy<PrimConv<PT_MemberPtr>::T>;270  default:271    return nullptr;272  }273  llvm_unreachable("Unhandled PrimType");274}275 276static BlockCtorFn getCtorArrayPrim(PrimType Type) {277  TYPE_SWITCH(Type, return ctorArrayTy<T>);278  llvm_unreachable("unknown Expr");279}280 281static BlockDtorFn getDtorArrayPrim(PrimType Type) {282  TYPE_SWITCH(Type, return dtorArrayTy<T>);283  llvm_unreachable("unknown Expr");284}285 286/// Primitives.287Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,288                       MetadataSize MD, bool IsConst, bool IsTemporary,289                       bool IsMutable, bool IsVolatile)290    : Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),291      MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),292      IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),293      IsVolatile(IsVolatile), CtorFn(getCtorPrim(Type)),294      DtorFn(getDtorPrim(Type)) {295  assert(AllocSize >= Size);296  assert(Source && "Missing source");297}298 299/// Primitive arrays.300Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,301                       size_t NumElems, bool IsConst, bool IsTemporary,302                       bool IsMutable)303    : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),304      MDSize(MD.value_or(0)),305      AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),306      IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),307      IsArray(true), CtorFn(getCtorArrayPrim(Type)),308      DtorFn(getDtorArrayPrim(Type)) {309  assert(Source && "Missing source");310  assert(NumElems <= (MaxArrayElemBytes / ElemSize));311}312 313/// Primitive unknown-size arrays.314Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,315                       bool IsTemporary, bool IsConst, UnknownSize)316    : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),317      MDSize(MD.value_or(0)),318      AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),319      IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary),320      IsArray(true), CtorFn(getCtorArrayPrim(Type)),321      DtorFn(getDtorArrayPrim(Type)) {322  assert(Source && "Missing source");323}324 325/// Arrays of composite elements.326Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy,327                       const Descriptor *Elem, MetadataSize MD,328                       unsigned NumElems, bool IsConst, bool IsTemporary,329                       bool IsMutable)330    : Source(D), SourceType(SourceTy),331      ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),332      Size(ElemSize * NumElems), MDSize(MD.value_or(0)),333      AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),334      ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),335      IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),336      DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) {337  assert(Source && "Missing source");338}339 340/// Unknown-size arrays of composite elements.341Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,342                       bool IsTemporary, UnknownSize)343    : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),344      Size(UnknownSizeMark), MDSize(MD.value_or(0)),345      AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),346      IsMutable(false), IsTemporary(IsTemporary), IsArray(true),347      CtorFn(ctorArrayDesc), DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) {348  assert(Source && "Missing source");349}350 351/// Composite records.352Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,353                       bool IsConst, bool IsTemporary, bool IsMutable,354                       bool IsVolatile)355    : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),356      Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),357      ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),358      IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(ctorRecord),359      DtorFn(needsRecordDtor(R) ? dtorRecord : nullptr) {360  assert(Source && "Missing source");361}362 363/// Dummy.364Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)365    : Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)),366      AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),367      IsTemporary(false) {368  assert(Source && "Missing source");369}370 371QualType Descriptor::getType() const {372  if (SourceType)373    return QualType(SourceType, 0);374  if (const auto *D = asValueDecl())375    return D->getType();376  if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))377    return T->getASTContext().getTypeDeclType(T);378 379  // The Source sometimes has a different type than the once380  // we really save. Try to consult the Record first.381  if (isRecord()) {382    const RecordDecl *RD = ElemRecord->getDecl();383    return RD->getASTContext().getCanonicalTagType(RD);384  }385  if (const auto *E = asExpr())386    return E->getType();387  llvm_unreachable("Invalid descriptor type");388}389 390QualType Descriptor::getElemQualType() const {391  assert(isArray());392  QualType T = getType();393  if (T->isPointerOrReferenceType())394    T = T->getPointeeType();395 396  if (const auto *AT = T->getAsArrayTypeUnsafe()) {397    // For primitive arrays, we don't save a QualType at all,398    // just a PrimType. Try to figure out the QualType here.399    if (isPrimitiveArray()) {400      while (T->isArrayType())401        T = T->getAsArrayTypeUnsafe()->getElementType();402      return T;403    }404    return AT->getElementType();405  }406  if (const auto *CT = T->getAs<ComplexType>())407    return CT->getElementType();408  if (const auto *CT = T->getAs<VectorType>())409    return CT->getElementType();410 411  return T;412}413 414QualType Descriptor::getDataType(const ASTContext &Ctx) const {415  auto MakeArrayType = [&](QualType ElemType) -> QualType {416    if (IsArray)417      return Ctx.getConstantArrayType(418          ElemType, APInt(64, static_cast<uint64_t>(getNumElems()), false),419          nullptr, ArraySizeModifier::Normal, 0);420    return ElemType;421  };422 423  if (const auto *E = asExpr()) {424    if (isa<CXXNewExpr>(E))425      return MakeArrayType(E->getType()->getPointeeType());426 427    // std::allocator.allocate() call.428    if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);429        ME && ME->getRecordDecl()->getName() == "allocator" &&430        ME->getMethodDecl()->getName() == "allocate")431      return MakeArrayType(E->getType()->getPointeeType());432    return E->getType();433  }434 435  return getType();436}437 438SourceLocation Descriptor::getLocation() const {439  if (auto *D = dyn_cast<const Decl *>(Source))440    return D->getLocation();441  if (auto *E = dyn_cast<const Expr *>(Source))442    return E->getExprLoc();443  llvm_unreachable("Invalid descriptor type");444}445 446SourceInfo Descriptor::getLoc() const {447  if (const auto *D = dyn_cast<const Decl *>(Source))448    return SourceInfo(D);449  if (const auto *E = dyn_cast<const Expr *>(Source))450    return SourceInfo(E);451  llvm_unreachable("Invalid descriptor type");452}453 454bool Descriptor::hasTrivialDtor() const {455  if (isPrimitive() || isPrimitiveArray())456    return true;457 458  if (isRecord()) {459    assert(ElemRecord);460    return ElemRecord->hasTrivialDtor();461  }462 463  if (!ElemDesc)464    return true;465  // Composite arrays.466  return ElemDesc->hasTrivialDtor();467}468 469bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }470 471InitMap::InitMap(unsigned N)472    : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}473 474bool InitMap::initializeElement(unsigned I) {475  unsigned Bucket = I / PER_FIELD;476  T Mask = T(1) << (I % PER_FIELD);477  if (!(data()[Bucket] & Mask)) {478    data()[Bucket] |= Mask;479    UninitFields -= 1;480  }481  return UninitFields == 0;482}483 484bool InitMap::isElementInitialized(unsigned I) const {485  unsigned Bucket = I / PER_FIELD;486  return data()[Bucket] & (T(1) << (I % PER_FIELD));487}488