Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp
35291 views
//===--- Program.cpp - Bytecode 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 "Program.h"9#include "Context.h"10#include "Function.h"11#include "Integral.h"12#include "Opcode.h"13#include "PrimType.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclCXX.h"1617using namespace clang;18using namespace clang::interp;1920unsigned Program::getOrCreateNativePointer(const void *Ptr) {21auto It = NativePointerIndices.find(Ptr);22if (It != NativePointerIndices.end())23return It->second;2425unsigned Idx = NativePointers.size();26NativePointers.push_back(Ptr);27NativePointerIndices[Ptr] = Idx;28return Idx;29}3031const void *Program::getNativePointer(unsigned Idx) {32return NativePointers[Idx];33}3435unsigned Program::createGlobalString(const StringLiteral *S) {36const size_t CharWidth = S->getCharByteWidth();37const size_t BitWidth = CharWidth * Ctx.getCharBit();3839PrimType CharType;40switch (CharWidth) {41case 1:42CharType = PT_Sint8;43break;44case 2:45CharType = PT_Uint16;46break;47case 4:48CharType = PT_Uint32;49break;50default:51llvm_unreachable("unsupported character width");52}5354// Create a descriptor for the string.55Descriptor *Desc =56allocateDescriptor(S, CharType, Descriptor::GlobalMD, S->getLength() + 1,57/*isConst=*/true,58/*isTemporary=*/false,59/*isMutable=*/false);6061// Allocate storage for the string.62// The byte length does not include the null terminator.63unsigned I = Globals.size();64unsigned Sz = Desc->getAllocSize();65auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true,66/*isExtern=*/false);67G->block()->invokeCtor();6869new (G->block()->rawData()) InlineDescriptor(Desc);70Globals.push_back(G);7172// Construct the string in storage.73const Pointer Ptr(G->block());74for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {75Pointer Field = Ptr.atIndex(I).narrow();76const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);77switch (CharType) {78case PT_Sint8: {79using T = PrimConv<PT_Sint8>::T;80Field.deref<T>() = T::from(CodePoint, BitWidth);81Field.initialize();82break;83}84case PT_Uint16: {85using T = PrimConv<PT_Uint16>::T;86Field.deref<T>() = T::from(CodePoint, BitWidth);87Field.initialize();88break;89}90case PT_Uint32: {91using T = PrimConv<PT_Uint32>::T;92Field.deref<T>() = T::from(CodePoint, BitWidth);93Field.initialize();94break;95}96default:97llvm_unreachable("unsupported character type");98}99}100return I;101}102103Pointer Program::getPtrGlobal(unsigned Idx) const {104assert(Idx < Globals.size());105return Pointer(Globals[Idx]->block());106}107108std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {109if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())110return It->second;111112// Find any previous declarations which were already evaluated.113std::optional<unsigned> Index;114for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) {115if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) {116Index = It->second;117break;118}119}120121// Map the decl to the existing index.122if (Index)123GlobalIndices[VD] = *Index;124125return std::nullopt;126}127128std::optional<unsigned> Program::getGlobal(const Expr *E) {129if (auto It = GlobalIndices.find(E); It != GlobalIndices.end())130return It->second;131return std::nullopt;132}133134std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,135const Expr *Init) {136if (auto Idx = getGlobal(VD))137return Idx;138139if (auto Idx = createGlobal(VD, Init)) {140GlobalIndices[VD] = *Idx;141return Idx;142}143return std::nullopt;144}145146std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {147// Dedup blocks since they are immutable and pointers cannot be compared.148if (auto It = DummyVariables.find(VD); It != DummyVariables.end())149return It->second;150151QualType QT = VD->getType();152if (const auto *RT = QT->getAs<ReferenceType>())153QT = RT->getPointeeType();154155Descriptor *Desc;156if (std::optional<PrimType> T = Ctx.classify(QT))157Desc = createDescriptor(VD, *T, std::nullopt, true, false);158else159Desc = createDescriptor(VD, QT.getTypePtr(), std::nullopt, true, false);160if (!Desc)161Desc = allocateDescriptor(VD);162163assert(Desc);164Desc->makeDummy();165166assert(Desc->isDummy());167168// Allocate a block for storage.169unsigned I = Globals.size();170171auto *G = new (Allocator, Desc->getAllocSize())172Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true,173/*IsExtern=*/false);174G->block()->invokeCtor();175176Globals.push_back(G);177DummyVariables[VD] = I;178return I;179}180181std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,182const Expr *Init) {183bool IsStatic, IsExtern;184if (const auto *Var = dyn_cast<VarDecl>(VD)) {185IsStatic = Context::shouldBeGloballyIndexed(VD);186IsExtern = Var->hasExternalStorage();187} else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl,188TemplateParamObjectDecl>(VD)) {189IsStatic = true;190IsExtern = false;191} else {192IsStatic = false;193IsExtern = true;194}195if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) {196for (const Decl *P = VD; P; P = P->getPreviousDecl())197GlobalIndices[P] = *Idx;198return *Idx;199}200return std::nullopt;201}202203std::optional<unsigned> Program::createGlobal(const Expr *E) {204if (auto Idx = getGlobal(E))205return Idx;206if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true,207/*isExtern=*/false)) {208GlobalIndices[E] = *Idx;209return *Idx;210}211return std::nullopt;212}213214std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,215bool IsStatic, bool IsExtern,216const Expr *Init) {217// Create a descriptor for the global.218Descriptor *Desc;219const bool IsConst = Ty.isConstQualified();220const bool IsTemporary = D.dyn_cast<const Expr *>();221if (std::optional<PrimType> T = Ctx.classify(Ty))222Desc = createDescriptor(D, *T, Descriptor::GlobalMD, IsConst, IsTemporary);223else224Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst,225IsTemporary);226227if (!Desc)228return std::nullopt;229230// Allocate a block for storage.231unsigned I = Globals.size();232233auto *G = new (Allocator, Desc->getAllocSize())234Global(Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern);235G->block()->invokeCtor();236237// Initialize InlineDescriptor fields.238auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor();239if (!Init)240GD->InitState = GlobalInitState::NoInitializer;241Globals.push_back(G);242243return I;244}245246Function *Program::getFunction(const FunctionDecl *F) {247F = F->getCanonicalDecl();248assert(F);249auto It = Funcs.find(F);250return It == Funcs.end() ? nullptr : It->second.get();251}252253Record *Program::getOrCreateRecord(const RecordDecl *RD) {254// Use the actual definition as a key.255RD = RD->getDefinition();256if (!RD)257return nullptr;258259if (!RD->isCompleteDefinition())260return nullptr;261262// Deduplicate records.263if (auto It = Records.find(RD); It != Records.end())264return It->second;265266// We insert nullptr now and replace that later, so recursive calls267// to this function with the same RecordDecl don't run into268// infinite recursion.269Records.insert({RD, nullptr});270271// Number of bytes required by fields and base classes.272unsigned BaseSize = 0;273// Number of bytes required by virtual base.274unsigned VirtSize = 0;275276// Helper to get a base descriptor.277auto GetBaseDesc = [this](const RecordDecl *BD,278const Record *BR) -> const Descriptor * {279if (!BR)280return nullptr;281return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,282/*isTemporary=*/false,283/*isMutable=*/false);284};285286// Reserve space for base classes.287Record::BaseList Bases;288Record::VirtualBaseList VirtBases;289if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {290for (const CXXBaseSpecifier &Spec : CD->bases()) {291if (Spec.isVirtual())292continue;293294// In error cases, the base might not be a RecordType.295const auto *RT = Spec.getType()->getAs<RecordType>();296if (!RT)297return nullptr;298const RecordDecl *BD = RT->getDecl();299const Record *BR = getOrCreateRecord(BD);300301const Descriptor *Desc = GetBaseDesc(BD, BR);302if (!Desc)303return nullptr;304305BaseSize += align(sizeof(InlineDescriptor));306Bases.push_back({BD, BaseSize, Desc, BR});307BaseSize += align(BR->getSize());308}309310for (const CXXBaseSpecifier &Spec : CD->vbases()) {311const auto *RT = Spec.getType()->getAs<RecordType>();312if (!RT)313return nullptr;314315const RecordDecl *BD = RT->getDecl();316const Record *BR = getOrCreateRecord(BD);317318const Descriptor *Desc = GetBaseDesc(BD, BR);319if (!Desc)320return nullptr;321322VirtSize += align(sizeof(InlineDescriptor));323VirtBases.push_back({BD, VirtSize, Desc, BR});324VirtSize += align(BR->getSize());325}326}327328// Reserve space for fields.329Record::FieldList Fields;330for (const FieldDecl *FD : RD->fields()) {331// Note that we DO create fields and descriptors332// for unnamed bitfields here, even though we later ignore333// them everywhere. That's so the FieldDecl's getFieldIndex() matches.334335// Reserve space for the field's descriptor and the offset.336BaseSize += align(sizeof(InlineDescriptor));337338// Classify the field and add its metadata.339QualType FT = FD->getType();340const bool IsConst = FT.isConstQualified();341const bool IsMutable = FD->isMutable();342const Descriptor *Desc;343if (std::optional<PrimType> T = Ctx.classify(FT)) {344Desc = createDescriptor(FD, *T, std::nullopt, IsConst,345/*isTemporary=*/false, IsMutable);346} else {347Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,348/*isTemporary=*/false, IsMutable);349}350if (!Desc)351return nullptr;352Fields.push_back({FD, BaseSize, Desc});353BaseSize += align(Desc->getAllocSize());354}355356Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),357std::move(VirtBases), VirtSize, BaseSize);358Records[RD] = R;359return R;360}361362Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,363Descriptor::MetadataSize MDSize,364bool IsConst, bool IsTemporary,365bool IsMutable, const Expr *Init) {366367// Classes and structures.368if (const auto *RT = Ty->getAs<RecordType>()) {369if (const auto *Record = getOrCreateRecord(RT->getDecl()))370return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,371IsMutable);372}373374// Arrays.375if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) {376QualType ElemTy = ArrayType->getElementType();377// Array of well-known bounds.378if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {379size_t NumElems = CAT->getZExtSize();380if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {381// Arrays of primitives.382unsigned ElemSize = primSize(*T);383if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {384return {};385}386return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary,387IsMutable);388} else {389// Arrays of composites. In this case, the array is a list of pointers,390// followed by the actual elements.391const Descriptor *ElemDesc = createDescriptor(392D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);393if (!ElemDesc)394return nullptr;395unsigned ElemSize =396ElemDesc->getAllocSize() + sizeof(InlineDescriptor);397if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)398return {};399return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst,400IsTemporary, IsMutable);401}402}403404// Array of unknown bounds - cannot be accessed and pointer arithmetic405// is forbidden on pointers to such objects.406if (isa<IncompleteArrayType>(ArrayType) ||407isa<VariableArrayType>(ArrayType)) {408if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {409return allocateDescriptor(D, *T, MDSize, IsTemporary,410Descriptor::UnknownSize{});411} else {412const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(),413MDSize, IsConst, IsTemporary);414if (!Desc)415return nullptr;416return allocateDescriptor(D, Desc, MDSize, IsTemporary,417Descriptor::UnknownSize{});418}419}420}421422// Atomic types.423if (const auto *AT = Ty->getAs<AtomicType>()) {424const Type *InnerTy = AT->getValueType().getTypePtr();425return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,426IsMutable);427}428429// Complex types - represented as arrays of elements.430if (const auto *CT = Ty->getAs<ComplexType>()) {431PrimType ElemTy = *Ctx.classify(CT->getElementType());432return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,433IsMutable);434}435436// Same with vector types.437if (const auto *VT = Ty->getAs<VectorType>()) {438PrimType ElemTy = *Ctx.classify(VT->getElementType());439return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst,440IsTemporary, IsMutable);441}442443return nullptr;444}445446447