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