1a07aba5dSTimm Baeder //===--- Program.h - Bytecode for the constexpr VM --------------*- C++ -*-===// 2a07aba5dSTimm Baeder // 3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a07aba5dSTimm Baeder // 7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 8a07aba5dSTimm Baeder // 9a07aba5dSTimm Baeder // Defines a program which organises and links multiple bytecode functions. 10a07aba5dSTimm Baeder // 11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 12a07aba5dSTimm Baeder 13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H 14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_PROGRAM_H 15a07aba5dSTimm Baeder 16a07aba5dSTimm Baeder #include "Function.h" 17a07aba5dSTimm Baeder #include "Pointer.h" 18a07aba5dSTimm Baeder #include "PrimType.h" 19a07aba5dSTimm Baeder #include "Record.h" 20a07aba5dSTimm Baeder #include "Source.h" 21a07aba5dSTimm Baeder #include "llvm/ADT/DenseMap.h" 22a07aba5dSTimm Baeder #include "llvm/ADT/PointerUnion.h" 23a07aba5dSTimm Baeder #include "llvm/ADT/StringRef.h" 24a07aba5dSTimm Baeder #include "llvm/Support/Allocator.h" 25a07aba5dSTimm Baeder #include <map> 26a07aba5dSTimm Baeder #include <vector> 27a07aba5dSTimm Baeder 28a07aba5dSTimm Baeder namespace clang { 29a07aba5dSTimm Baeder class RecordDecl; 30a07aba5dSTimm Baeder class Expr; 31a07aba5dSTimm Baeder class FunctionDecl; 32a07aba5dSTimm Baeder class StringLiteral; 33a07aba5dSTimm Baeder class VarDecl; 34a07aba5dSTimm Baeder 35a07aba5dSTimm Baeder namespace interp { 36a07aba5dSTimm Baeder class Context; 37a07aba5dSTimm Baeder 38a07aba5dSTimm Baeder /// The program contains and links the bytecode for all functions. 39a07aba5dSTimm Baeder class Program final { 40a07aba5dSTimm Baeder public: 41a07aba5dSTimm Baeder Program(Context &Ctx) : Ctx(Ctx) {} 42a07aba5dSTimm Baeder 43a07aba5dSTimm Baeder ~Program() { 44a07aba5dSTimm Baeder // Manually destroy all the blocks. They are almost all harmless, 45a07aba5dSTimm Baeder // but primitive arrays might have an InitMap* heap allocated and 46a07aba5dSTimm Baeder // that needs to be freed. 47a07aba5dSTimm Baeder for (Global *G : Globals) 48a07aba5dSTimm Baeder if (Block *B = G->block(); B->isInitialized()) 49a07aba5dSTimm Baeder B->invokeDtor(); 50a07aba5dSTimm Baeder 51a07aba5dSTimm Baeder // Records might actually allocate memory themselves, but they 52a07aba5dSTimm Baeder // are allocated using a BumpPtrAllocator. Call their desctructors 53a07aba5dSTimm Baeder // here manually so they are properly freeing their resources. 54a07aba5dSTimm Baeder for (auto RecordPair : Records) { 55a07aba5dSTimm Baeder if (Record *R = RecordPair.second) 56a07aba5dSTimm Baeder R->~Record(); 57a07aba5dSTimm Baeder } 58a07aba5dSTimm Baeder } 59a07aba5dSTimm Baeder 60a07aba5dSTimm Baeder /// Marshals a native pointer to an ID for embedding in bytecode. 61a07aba5dSTimm Baeder unsigned getOrCreateNativePointer(const void *Ptr); 62a07aba5dSTimm Baeder 63a07aba5dSTimm Baeder /// Returns the value of a marshalled native pointer. 64a07aba5dSTimm Baeder const void *getNativePointer(unsigned Idx); 65a07aba5dSTimm Baeder 66a07aba5dSTimm Baeder /// Emits a string literal among global data. 67ff04bb8fSTimm Baeder unsigned createGlobalString(const StringLiteral *S, 68ff04bb8fSTimm Baeder const Expr *Base = nullptr); 69a07aba5dSTimm Baeder 70a07aba5dSTimm Baeder /// Returns a pointer to a global. 71a07aba5dSTimm Baeder Pointer getPtrGlobal(unsigned Idx) const; 72a07aba5dSTimm Baeder 73a07aba5dSTimm Baeder /// Returns the value of a global. 74a07aba5dSTimm Baeder Block *getGlobal(unsigned Idx) { 75a07aba5dSTimm Baeder assert(Idx < Globals.size()); 76a07aba5dSTimm Baeder return Globals[Idx]->block(); 77a07aba5dSTimm Baeder } 78a07aba5dSTimm Baeder 79a07aba5dSTimm Baeder /// Finds a global's index. 80a07aba5dSTimm Baeder std::optional<unsigned> getGlobal(const ValueDecl *VD); 81a07aba5dSTimm Baeder std::optional<unsigned> getGlobal(const Expr *E); 82a07aba5dSTimm Baeder 83a07aba5dSTimm Baeder /// Returns or creates a global an creates an index to it. 84a07aba5dSTimm Baeder std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD, 85a07aba5dSTimm Baeder const Expr *Init = nullptr); 86a07aba5dSTimm Baeder 87a07aba5dSTimm Baeder /// Returns or creates a dummy value for unknown declarations. 889ae41c24STimm Baeder unsigned getOrCreateDummy(const DeclTy &D); 89a07aba5dSTimm Baeder 90a07aba5dSTimm Baeder /// Creates a global and returns its index. 91a07aba5dSTimm Baeder std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init); 92a07aba5dSTimm Baeder 93a07aba5dSTimm Baeder /// Creates a global from a lifetime-extended temporary. 94a07aba5dSTimm Baeder std::optional<unsigned> createGlobal(const Expr *E); 95a07aba5dSTimm Baeder 96a07aba5dSTimm Baeder /// Creates a new function from a code range. 97a07aba5dSTimm Baeder template <typename... Ts> 98a07aba5dSTimm Baeder Function *createFunction(const FunctionDecl *Def, Ts &&...Args) { 99a07aba5dSTimm Baeder Def = Def->getCanonicalDecl(); 100a07aba5dSTimm Baeder auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...); 101a07aba5dSTimm Baeder Funcs.insert({Def, std::unique_ptr<Function>(Func)}); 102a07aba5dSTimm Baeder return Func; 103a07aba5dSTimm Baeder } 104a07aba5dSTimm Baeder /// Creates an anonymous function. 105a07aba5dSTimm Baeder template <typename... Ts> Function *createFunction(Ts &&...Args) { 106a07aba5dSTimm Baeder auto *Func = new Function(*this, std::forward<Ts>(Args)...); 107a07aba5dSTimm Baeder AnonFuncs.emplace_back(Func); 108a07aba5dSTimm Baeder return Func; 109a07aba5dSTimm Baeder } 110a07aba5dSTimm Baeder 111a07aba5dSTimm Baeder /// Returns a function. 112a07aba5dSTimm Baeder Function *getFunction(const FunctionDecl *F); 113a07aba5dSTimm Baeder 114a07aba5dSTimm Baeder /// Returns a record or creates one if it does not exist. 115a07aba5dSTimm Baeder Record *getOrCreateRecord(const RecordDecl *RD); 116a07aba5dSTimm Baeder 117a07aba5dSTimm Baeder /// Creates a descriptor for a primitive type. 118a07aba5dSTimm Baeder Descriptor *createDescriptor(const DeclTy &D, PrimType Type, 119a07aba5dSTimm Baeder Descriptor::MetadataSize MDSize = std::nullopt, 120a07aba5dSTimm Baeder bool IsConst = false, bool IsTemporary = false, 121a07aba5dSTimm Baeder bool IsMutable = false) { 122a07aba5dSTimm Baeder return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable); 123a07aba5dSTimm Baeder } 124a07aba5dSTimm Baeder 125a07aba5dSTimm Baeder /// Creates a descriptor for a composite type. 126a07aba5dSTimm Baeder Descriptor *createDescriptor(const DeclTy &D, const Type *Ty, 127a07aba5dSTimm Baeder Descriptor::MetadataSize MDSize = std::nullopt, 128a07aba5dSTimm Baeder bool IsConst = false, bool IsTemporary = false, 129a07aba5dSTimm Baeder bool IsMutable = false, 130a07aba5dSTimm Baeder const Expr *Init = nullptr); 131a07aba5dSTimm Baeder 132a07aba5dSTimm Baeder /// Context to manage declaration lifetimes. 133a07aba5dSTimm Baeder class DeclScope { 134a07aba5dSTimm Baeder public: 135a07aba5dSTimm Baeder DeclScope(Program &P, const ValueDecl *VD) : P(P) { 136a07aba5dSTimm Baeder P.startDeclaration(VD); 137a07aba5dSTimm Baeder } 138a07aba5dSTimm Baeder ~DeclScope() { P.endDeclaration(); } 139a07aba5dSTimm Baeder 140a07aba5dSTimm Baeder private: 141a07aba5dSTimm Baeder Program &P; 142a07aba5dSTimm Baeder }; 143a07aba5dSTimm Baeder 144a07aba5dSTimm Baeder /// Returns the current declaration ID. 145a07aba5dSTimm Baeder std::optional<unsigned> getCurrentDecl() const { 146a07aba5dSTimm Baeder if (CurrentDeclaration == NoDeclaration) 147a07aba5dSTimm Baeder return std::optional<unsigned>{}; 148a07aba5dSTimm Baeder return LastDeclaration; 149a07aba5dSTimm Baeder } 150a07aba5dSTimm Baeder 151a07aba5dSTimm Baeder private: 152a07aba5dSTimm Baeder friend class DeclScope; 153a07aba5dSTimm Baeder 154a07aba5dSTimm Baeder std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty, 155a07aba5dSTimm Baeder bool IsStatic, bool IsExtern, 1564e5f8a8fSTimm Baeder bool IsWeak, const Expr *Init = nullptr); 157a07aba5dSTimm Baeder 158a07aba5dSTimm Baeder /// Reference to the VM context. 159a07aba5dSTimm Baeder Context &Ctx; 160a07aba5dSTimm Baeder /// Mapping from decls to cached bytecode functions. 161a07aba5dSTimm Baeder llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs; 162a07aba5dSTimm Baeder /// List of anonymous functions. 163a07aba5dSTimm Baeder std::vector<std::unique_ptr<Function>> AnonFuncs; 164a07aba5dSTimm Baeder 165a07aba5dSTimm Baeder /// Function relocation locations. 166a07aba5dSTimm Baeder llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs; 167a07aba5dSTimm Baeder 168a07aba5dSTimm Baeder /// Native pointers referenced by bytecode. 169a07aba5dSTimm Baeder std::vector<const void *> NativePointers; 170a07aba5dSTimm Baeder /// Cached native pointer indices. 171a07aba5dSTimm Baeder llvm::DenseMap<const void *, unsigned> NativePointerIndices; 172a07aba5dSTimm Baeder 173a07aba5dSTimm Baeder /// Custom allocator for global storage. 174*de18fa1aSRichard Smith using PoolAllocTy = llvm::BumpPtrAllocator; 175a07aba5dSTimm Baeder 176a07aba5dSTimm Baeder /// Descriptor + storage for a global object. 177a07aba5dSTimm Baeder /// 178a07aba5dSTimm Baeder /// Global objects never go out of scope, thus they do not track pointers. 179a07aba5dSTimm Baeder class Global { 180a07aba5dSTimm Baeder public: 181a07aba5dSTimm Baeder /// Create a global descriptor for string literals. 182a07aba5dSTimm Baeder template <typename... Tys> 183a07aba5dSTimm Baeder Global(Tys... Args) : B(std::forward<Tys>(Args)...) {} 184a07aba5dSTimm Baeder 185a07aba5dSTimm Baeder /// Allocates the global in the pool, reserving storate for data. 186a07aba5dSTimm Baeder void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) { 187a07aba5dSTimm Baeder return Alloc.Allocate(Meta + Data, alignof(void *)); 188a07aba5dSTimm Baeder } 189a07aba5dSTimm Baeder 190a07aba5dSTimm Baeder /// Return a pointer to the data. 191a07aba5dSTimm Baeder std::byte *data() { return B.data(); } 192a07aba5dSTimm Baeder /// Return a pointer to the block. 193a07aba5dSTimm Baeder Block *block() { return &B; } 194a07aba5dSTimm Baeder const Block *block() const { return &B; } 195a07aba5dSTimm Baeder 196a07aba5dSTimm Baeder private: 197a07aba5dSTimm Baeder /// Required metadata - does not actually track pointers. 198a07aba5dSTimm Baeder Block B; 199a07aba5dSTimm Baeder }; 200a07aba5dSTimm Baeder 201a07aba5dSTimm Baeder /// Allocator for globals. 202a07aba5dSTimm Baeder PoolAllocTy Allocator; 203a07aba5dSTimm Baeder 204a07aba5dSTimm Baeder /// Global objects. 205a07aba5dSTimm Baeder std::vector<Global *> Globals; 206a07aba5dSTimm Baeder /// Cached global indices. 207a07aba5dSTimm Baeder llvm::DenseMap<const void *, unsigned> GlobalIndices; 208a07aba5dSTimm Baeder 209a07aba5dSTimm Baeder /// Mapping from decls to record metadata. 210a07aba5dSTimm Baeder llvm::DenseMap<const RecordDecl *, Record *> Records; 211a07aba5dSTimm Baeder 212a07aba5dSTimm Baeder /// Dummy parameter to generate pointers from. 213bd8d432dSTimm Baeder llvm::DenseMap<const void *, unsigned> DummyVariables; 214a07aba5dSTimm Baeder 215a07aba5dSTimm Baeder /// Creates a new descriptor. 216a07aba5dSTimm Baeder template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) { 217a07aba5dSTimm Baeder return new (Allocator) Descriptor(std::forward<Ts>(Args)...); 218a07aba5dSTimm Baeder } 219a07aba5dSTimm Baeder 220a07aba5dSTimm Baeder /// No declaration ID. 221a07aba5dSTimm Baeder static constexpr unsigned NoDeclaration = (unsigned)-1; 222a07aba5dSTimm Baeder /// Last declaration ID. 223a07aba5dSTimm Baeder unsigned LastDeclaration = 0; 224a07aba5dSTimm Baeder /// Current declaration ID. 225a07aba5dSTimm Baeder unsigned CurrentDeclaration = NoDeclaration; 226a07aba5dSTimm Baeder 227a07aba5dSTimm Baeder /// Starts evaluating a declaration. 228a07aba5dSTimm Baeder void startDeclaration(const ValueDecl *Decl) { 229a07aba5dSTimm Baeder LastDeclaration += 1; 230a07aba5dSTimm Baeder CurrentDeclaration = LastDeclaration; 231a07aba5dSTimm Baeder } 232a07aba5dSTimm Baeder 233a07aba5dSTimm Baeder /// Ends a global declaration. 234a07aba5dSTimm Baeder void endDeclaration() { CurrentDeclaration = NoDeclaration; } 235a07aba5dSTimm Baeder 236a07aba5dSTimm Baeder public: 237a07aba5dSTimm Baeder /// Dumps the disassembled bytecode to \c llvm::errs(). 238a07aba5dSTimm Baeder void dump() const; 239a07aba5dSTimm Baeder void dump(llvm::raw_ostream &OS) const; 240a07aba5dSTimm Baeder }; 241a07aba5dSTimm Baeder 242a07aba5dSTimm Baeder } // namespace interp 243a07aba5dSTimm Baeder } // namespace clang 244a07aba5dSTimm Baeder 245a07aba5dSTimm Baeder #endif 246