|  | //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Program.h" | 
|  | #include "ByteCodeStmtGen.h" | 
|  | #include "Context.h" | 
|  | #include "Function.h" | 
|  | #include "Opcode.h" | 
|  | #include "Type.h" | 
|  | #include "clang/AST/Decl.h" | 
|  | #include "clang/AST/DeclCXX.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace clang::interp; | 
|  |  | 
|  | unsigned Program::createGlobalString(const StringLiteral *S) { | 
|  | const size_t CharWidth = S->getCharByteWidth(); | 
|  | const size_t BitWidth = CharWidth * Ctx.getCharBit(); | 
|  |  | 
|  | PrimType CharType; | 
|  | switch (CharWidth) { | 
|  | case 1: | 
|  | CharType = PT_Sint8; | 
|  | break; | 
|  | case 2: | 
|  | CharType = PT_Uint16; | 
|  | break; | 
|  | case 4: | 
|  | CharType = PT_Uint32; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unsupported character width"); | 
|  | } | 
|  |  | 
|  | // Create a descriptor for the string. | 
|  | Descriptor *Desc = allocateDescriptor(S, CharType, S->getLength() + 1, | 
|  | /*isConst=*/true, | 
|  | /*isTemporary=*/false, | 
|  | /*isMutable=*/false); | 
|  |  | 
|  | // Allocate storage for the string. | 
|  | // The byte length does not include the null terminator. | 
|  | unsigned I = Globals.size(); | 
|  | unsigned Sz = Desc->getAllocSize(); | 
|  | auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true, | 
|  | /*isExtern=*/false); | 
|  | Globals.push_back(G); | 
|  |  | 
|  | // Construct the string in storage. | 
|  | const Pointer Ptr(G->block()); | 
|  | for (unsigned I = 0, N = S->getLength(); I <= N; ++I) { | 
|  | Pointer Field = Ptr.atIndex(I).narrow(); | 
|  | const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I); | 
|  | switch (CharType) { | 
|  | case PT_Sint8: { | 
|  | using T = PrimConv<PT_Sint8>::T; | 
|  | Field.deref<T>() = T::from(CodePoint, BitWidth); | 
|  | break; | 
|  | } | 
|  | case PT_Uint16: { | 
|  | using T = PrimConv<PT_Uint16>::T; | 
|  | Field.deref<T>() = T::from(CodePoint, BitWidth); | 
|  | break; | 
|  | } | 
|  | case PT_Uint32: { | 
|  | using T = PrimConv<PT_Uint32>::T; | 
|  | Field.deref<T>() = T::from(CodePoint, BitWidth); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | llvm_unreachable("unsupported character type"); | 
|  | } | 
|  | } | 
|  | return I; | 
|  | } | 
|  |  | 
|  | Pointer Program::getPtrGlobal(unsigned Idx) { | 
|  | assert(Idx < Globals.size()); | 
|  | return Pointer(Globals[Idx]->block()); | 
|  | } | 
|  |  | 
|  | llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) { | 
|  | auto It = GlobalIndices.find(VD); | 
|  | if (It != GlobalIndices.end()) | 
|  | return It->second; | 
|  |  | 
|  | // Find any previous declarations which were aleady evaluated. | 
|  | llvm::Optional<unsigned> Index; | 
|  | for (const Decl *P = VD; P; P = P->getPreviousDecl()) { | 
|  | auto It = GlobalIndices.find(P); | 
|  | if (It != GlobalIndices.end()) { | 
|  | Index = It->second; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Map the decl to the existing index. | 
|  | if (Index) { | 
|  | GlobalIndices[VD] = *Index; | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | return Index; | 
|  | } | 
|  |  | 
|  | llvm::Optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD) { | 
|  | if (auto Idx = getGlobal(VD)) | 
|  | return Idx; | 
|  |  | 
|  | if (auto Idx = createGlobal(VD)) { | 
|  | GlobalIndices[VD] = *Idx; | 
|  | return Idx; | 
|  | } | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) { | 
|  | auto &ASTCtx = Ctx.getASTContext(); | 
|  |  | 
|  | // Create a pointer to an incomplete array of the specified elements. | 
|  | QualType ElemTy = PD->getType()->getAs<PointerType>()->getPointeeType(); | 
|  | QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0); | 
|  |  | 
|  | // Dedup blocks since they are immutable and pointers cannot be compared. | 
|  | auto It = DummyParams.find(PD); | 
|  | if (It != DummyParams.end()) | 
|  | return It->second; | 
|  |  | 
|  | if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) { | 
|  | DummyParams[PD] = *Idx; | 
|  | return Idx; | 
|  | } | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) { | 
|  | bool IsStatic, IsExtern; | 
|  | if (auto *Var = dyn_cast<VarDecl>(VD)) { | 
|  | IsStatic = !Var->hasLocalStorage(); | 
|  | IsExtern = !Var->getAnyInitializer(); | 
|  | } else { | 
|  | IsStatic = false; | 
|  | IsExtern = true; | 
|  | } | 
|  | if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) { | 
|  | for (const Decl *P = VD; P; P = P->getPreviousDecl()) | 
|  | GlobalIndices[P] = *Idx; | 
|  | return *Idx; | 
|  | } | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | llvm::Optional<unsigned> Program::createGlobal(const Expr *E) { | 
|  | return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false); | 
|  | } | 
|  |  | 
|  | llvm::Optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, | 
|  | bool IsStatic, bool IsExtern) { | 
|  | // Create a descriptor for the global. | 
|  | Descriptor *Desc; | 
|  | const bool IsConst = Ty.isConstQualified(); | 
|  | const bool IsTemporary = D.dyn_cast<const Expr *>(); | 
|  | if (auto T = Ctx.classify(Ty)) { | 
|  | Desc = createDescriptor(D, *T, IsConst, IsTemporary); | 
|  | } else { | 
|  | Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary); | 
|  | } | 
|  | if (!Desc) | 
|  | return {}; | 
|  |  | 
|  | // Allocate a block for storage. | 
|  | unsigned I = Globals.size(); | 
|  |  | 
|  | auto *G = new (Allocator, Desc->getAllocSize()) | 
|  | Global(getCurrentDecl(), Desc, IsStatic, IsExtern); | 
|  | G->block()->invokeCtor(); | 
|  |  | 
|  | Globals.push_back(G); | 
|  |  | 
|  | return I; | 
|  | } | 
|  |  | 
|  | Function *Program::getFunction(const FunctionDecl *F) { | 
|  | F = F->getDefinition(); | 
|  | auto It = Funcs.find(F); | 
|  | return It == Funcs.end() ? nullptr : It->second.get(); | 
|  | } | 
|  |  | 
|  | llvm::Expected<Function *> Program::getOrCreateFunction(const FunctionDecl *F) { | 
|  | if (Function *Func = getFunction(F)) { | 
|  | return Func; | 
|  | } | 
|  |  | 
|  | // Try to compile the function if it wasn't compiled yet. | 
|  | if (const FunctionDecl *FD = F->getDefinition()) | 
|  | return ByteCodeStmtGen<ByteCodeEmitter>(Ctx, *this).compileFunc(FD); | 
|  |  | 
|  | // A relocation which traps if not resolved. | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | Record *Program::getOrCreateRecord(const RecordDecl *RD) { | 
|  | // Use the actual definition as a key. | 
|  | RD = RD->getDefinition(); | 
|  | if (!RD) | 
|  | return nullptr; | 
|  |  | 
|  | // Deduplicate records. | 
|  | auto It = Records.find(RD); | 
|  | if (It != Records.end()) { | 
|  | return It->second; | 
|  | } | 
|  |  | 
|  | // Number of bytes required by fields and base classes. | 
|  | unsigned Size = 0; | 
|  | // Number of bytes required by virtual base. | 
|  | unsigned VirtSize = 0; | 
|  |  | 
|  | // Helper to get a base descriptor. | 
|  | auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * { | 
|  | if (!BR) | 
|  | return nullptr; | 
|  | return allocateDescriptor(BD, BR, /*isConst=*/false, | 
|  | /*isTemporary=*/false, | 
|  | /*isMutable=*/false); | 
|  | }; | 
|  |  | 
|  | // Reserve space for base classes. | 
|  | Record::BaseList Bases; | 
|  | Record::VirtualBaseList VirtBases; | 
|  | if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) { | 
|  | for (const CXXBaseSpecifier &Spec : CD->bases()) { | 
|  | if (Spec.isVirtual()) | 
|  | continue; | 
|  |  | 
|  | const RecordDecl *BD = Spec.getType()->getAs<RecordType>()->getDecl(); | 
|  | Record *BR = getOrCreateRecord(BD); | 
|  | if (Descriptor *Desc = GetBaseDesc(BD, BR)) { | 
|  | Size += align(sizeof(InlineDescriptor)); | 
|  | Bases.push_back({BD, Size, Desc, BR}); | 
|  | Size += align(BR->getSize()); | 
|  | continue; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | for (const CXXBaseSpecifier &Spec : CD->vbases()) { | 
|  | const RecordDecl *BD = Spec.getType()->getAs<RecordType>()->getDecl(); | 
|  | Record *BR = getOrCreateRecord(BD); | 
|  |  | 
|  | if (Descriptor *Desc = GetBaseDesc(BD, BR)) { | 
|  | VirtSize += align(sizeof(InlineDescriptor)); | 
|  | VirtBases.push_back({BD, VirtSize, Desc, BR}); | 
|  | VirtSize += align(BR->getSize()); | 
|  | continue; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Reserve space for fields. | 
|  | Record::FieldList Fields; | 
|  | for (const FieldDecl *FD : RD->fields()) { | 
|  | // Reserve space for the field's descriptor and the offset. | 
|  | Size += align(sizeof(InlineDescriptor)); | 
|  |  | 
|  | // Classify the field and add its metadata. | 
|  | QualType FT = FD->getType(); | 
|  | const bool IsConst = FT.isConstQualified(); | 
|  | const bool IsMutable = FD->isMutable(); | 
|  | Descriptor *Desc; | 
|  | if (llvm::Optional<PrimType> T = Ctx.classify(FT)) { | 
|  | Desc = createDescriptor(FD, *T, IsConst, /*isTemporary=*/false, | 
|  | IsMutable); | 
|  | } else { | 
|  | Desc = createDescriptor(FD, FT.getTypePtr(), IsConst, | 
|  | /*isTemporary=*/false, IsMutable); | 
|  | } | 
|  | if (!Desc) | 
|  | return nullptr; | 
|  | Fields.push_back({FD, Size, Desc}); | 
|  | Size += align(Desc->getAllocSize()); | 
|  | } | 
|  |  | 
|  | Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields), | 
|  | std::move(VirtBases), VirtSize, Size); | 
|  | Records.insert({RD, R}); | 
|  | return R; | 
|  | } | 
|  |  | 
|  | Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, | 
|  | bool IsConst, bool IsTemporary, | 
|  | bool IsMutable) { | 
|  | // Classes and structures. | 
|  | if (auto *RT = Ty->getAs<RecordType>()) { | 
|  | if (auto *Record = getOrCreateRecord(RT->getDecl())) | 
|  | return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable); | 
|  | } | 
|  |  | 
|  | // Arrays. | 
|  | if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) { | 
|  | QualType ElemTy = ArrayType->getElementType(); | 
|  | // Array of well-known bounds. | 
|  | if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) { | 
|  | size_t NumElems = CAT->getSize().getZExtValue(); | 
|  | if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) { | 
|  | // Arrays of primitives. | 
|  | unsigned ElemSize = primSize(*T); | 
|  | if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { | 
|  | return {}; | 
|  | } | 
|  | return allocateDescriptor(D, *T, NumElems, IsConst, IsTemporary, | 
|  | IsMutable); | 
|  | } else { | 
|  | // Arrays of composites. In this case, the array is a list of pointers, | 
|  | // followed by the actual elements. | 
|  | Descriptor *Desc = | 
|  | createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary); | 
|  | if (!Desc) | 
|  | return nullptr; | 
|  | InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor); | 
|  | if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) | 
|  | return {}; | 
|  | return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary, | 
|  | IsMutable); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Array of unknown bounds - cannot be accessed and pointer arithmetic | 
|  | // is forbidden on pointers to such objects. | 
|  | if (auto IAT = dyn_cast<IncompleteArrayType>(ArrayType)) { | 
|  | if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) { | 
|  | return allocateDescriptor(D, *T, IsTemporary, | 
|  | Descriptor::UnknownSize{}); | 
|  | } else { | 
|  | Descriptor *Desc = | 
|  | createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary); | 
|  | if (!Desc) | 
|  | return nullptr; | 
|  | return allocateDescriptor(D, Desc, IsTemporary, | 
|  | Descriptor::UnknownSize{}); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Atomic types. | 
|  | if (auto *AT = Ty->getAs<AtomicType>()) { | 
|  | const Type *InnerTy = AT->getValueType().getTypePtr(); | 
|  | return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable); | 
|  | } | 
|  |  | 
|  | // Complex types - represented as arrays of elements. | 
|  | if (auto *CT = Ty->getAs<ComplexType>()) { | 
|  | PrimType ElemTy = *Ctx.classify(CT->getElementType()); | 
|  | return allocateDescriptor(D, ElemTy, 2, IsConst, IsTemporary, IsMutable); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } |