xref: /llvm-project/clang/lib/AST/ByteCode/Program.h (revision de18fa1ace1cd717da9482a09d0a0db8666f48b7)
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