xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Program.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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 class Record;
38a7dea167SDimitry Andric 
39a7dea167SDimitry Andric /// The program contains and links the bytecode for all functions.
40bdd1243dSDimitry Andric class Program final {
41a7dea167SDimitry Andric public:
42a7dea167SDimitry Andric   Program(Context &Ctx) : Ctx(Ctx) {}
43a7dea167SDimitry Andric 
44bdd1243dSDimitry Andric   ~Program() {
45bdd1243dSDimitry Andric     // Manually destroy all the blocks. They are almost all harmless,
46bdd1243dSDimitry Andric     // but primitive arrays might have an InitMap* heap allocated and
47bdd1243dSDimitry Andric     // that needs to be freed.
48bdd1243dSDimitry Andric     for (Global *G : Globals)
49bdd1243dSDimitry Andric       G->block()->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.
70a7dea167SDimitry Andric   Pointer getPtrGlobal(unsigned Idx);
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);
80a7dea167SDimitry Andric 
81a7dea167SDimitry Andric   /// Returns or creates a global an creates an index to it.
82bdd1243dSDimitry Andric   std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
83bdd1243dSDimitry Andric                                             const Expr *Init = nullptr);
84a7dea167SDimitry Andric 
85a7dea167SDimitry Andric   /// Returns or creates a dummy value for parameters.
86bdd1243dSDimitry Andric   std::optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
87a7dea167SDimitry Andric 
88a7dea167SDimitry Andric   /// Creates a global and returns its index.
89bdd1243dSDimitry Andric   std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *E);
90a7dea167SDimitry Andric 
91a7dea167SDimitry Andric   /// Creates a global from a lifetime-extended temporary.
92bdd1243dSDimitry Andric   std::optional<unsigned> createGlobal(const Expr *E);
93a7dea167SDimitry Andric 
94a7dea167SDimitry Andric   /// Creates a new function from a code range.
95a7dea167SDimitry Andric   template <typename... Ts>
96a7dea167SDimitry Andric   Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
97bdd1243dSDimitry Andric     Def = Def->getCanonicalDecl();
98a7dea167SDimitry Andric     auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
99a7dea167SDimitry Andric     Funcs.insert({Def, std::unique_ptr<Function>(Func)});
100a7dea167SDimitry Andric     return Func;
101a7dea167SDimitry Andric   }
102a7dea167SDimitry Andric   /// Creates an anonymous function.
103a7dea167SDimitry Andric   template <typename... Ts>
104a7dea167SDimitry Andric   Function *createFunction(Ts &&... Args) {
105a7dea167SDimitry Andric     auto *Func = new Function(*this, std::forward<Ts>(Args)...);
106a7dea167SDimitry Andric     AnonFuncs.emplace_back(Func);
107a7dea167SDimitry Andric     return Func;
108a7dea167SDimitry Andric   }
109a7dea167SDimitry Andric 
110a7dea167SDimitry Andric   /// Returns a function.
111a7dea167SDimitry Andric   Function *getFunction(const FunctionDecl *F);
112a7dea167SDimitry Andric 
113a7dea167SDimitry Andric   /// Returns a record or creates one if it does not exist.
114a7dea167SDimitry Andric   Record *getOrCreateRecord(const RecordDecl *RD);
115a7dea167SDimitry Andric 
116a7dea167SDimitry Andric   /// Creates a descriptor for a primitive type.
117a7dea167SDimitry Andric   Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
118bdd1243dSDimitry Andric                                Descriptor::MetadataSize MDSize = std::nullopt,
119bdd1243dSDimitry Andric                                bool IsConst = false, bool IsTemporary = false,
120a7dea167SDimitry Andric                                bool IsMutable = false) {
121bdd1243dSDimitry Andric     return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
122a7dea167SDimitry Andric   }
123a7dea167SDimitry Andric 
124a7dea167SDimitry Andric   /// Creates a descriptor for a composite type.
125a7dea167SDimitry Andric   Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
126bdd1243dSDimitry Andric                                Descriptor::MetadataSize MDSize = std::nullopt,
127a7dea167SDimitry Andric                                bool IsConst = false, bool IsTemporary = false,
128bdd1243dSDimitry Andric                                bool IsMutable = false,
129bdd1243dSDimitry Andric                                const Expr *Init = nullptr);
130a7dea167SDimitry Andric 
131a7dea167SDimitry Andric   /// Context to manage declaration lifetimes.
132a7dea167SDimitry Andric   class DeclScope {
133a7dea167SDimitry Andric   public:
134*06c3fb27SDimitry Andric     DeclScope(Program &P, const ValueDecl *VD) : P(P) {
135*06c3fb27SDimitry Andric       P.startDeclaration(VD);
136*06c3fb27SDimitry Andric     }
137a7dea167SDimitry Andric     ~DeclScope() { P.endDeclaration(); }
138a7dea167SDimitry Andric 
139a7dea167SDimitry Andric   private:
140a7dea167SDimitry Andric     Program &P;
141a7dea167SDimitry Andric   };
142a7dea167SDimitry Andric 
143a7dea167SDimitry Andric   /// Returns the current declaration ID.
144bdd1243dSDimitry Andric   std::optional<unsigned> getCurrentDecl() const {
145a7dea167SDimitry Andric     if (CurrentDeclaration == NoDeclaration)
146bdd1243dSDimitry Andric       return std::optional<unsigned>{};
147a7dea167SDimitry Andric     return LastDeclaration;
148a7dea167SDimitry Andric   }
149a7dea167SDimitry Andric 
150a7dea167SDimitry Andric private:
151a7dea167SDimitry Andric   friend class DeclScope;
152a7dea167SDimitry Andric 
153bdd1243dSDimitry Andric   std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
154bdd1243dSDimitry Andric                                        bool IsStatic, bool IsExtern,
155bdd1243dSDimitry Andric                                        const Expr *Init = nullptr);
156a7dea167SDimitry Andric 
157a7dea167SDimitry Andric   /// Reference to the VM context.
158a7dea167SDimitry Andric   Context &Ctx;
159a7dea167SDimitry Andric   /// Mapping from decls to cached bytecode functions.
160a7dea167SDimitry Andric   llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
161a7dea167SDimitry Andric   /// List of anonymous functions.
162a7dea167SDimitry Andric   std::vector<std::unique_ptr<Function>> AnonFuncs;
163a7dea167SDimitry Andric 
164a7dea167SDimitry Andric   /// Function relocation locations.
165a7dea167SDimitry Andric   llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
166a7dea167SDimitry Andric 
167349cc55cSDimitry Andric   /// Native pointers referenced by bytecode.
168349cc55cSDimitry Andric   std::vector<const void *> NativePointers;
169349cc55cSDimitry Andric   /// Cached native pointer indices.
170349cc55cSDimitry Andric   llvm::DenseMap<const void *, unsigned> NativePointerIndices;
171349cc55cSDimitry Andric 
172a7dea167SDimitry Andric   /// Custom allocator for global storage.
173a7dea167SDimitry Andric   using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
174a7dea167SDimitry Andric 
175a7dea167SDimitry Andric   /// Descriptor + storage for a global object.
176a7dea167SDimitry Andric   ///
177a7dea167SDimitry Andric   /// Global objects never go out of scope, thus they do not track pointers.
178a7dea167SDimitry Andric   class Global {
179a7dea167SDimitry Andric   public:
180a7dea167SDimitry Andric     /// Create a global descriptor for string literals.
181a7dea167SDimitry Andric     template <typename... Tys>
182a7dea167SDimitry Andric     Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
183a7dea167SDimitry Andric 
184a7dea167SDimitry Andric     /// Allocates the global in the pool, reserving storate for data.
185a7dea167SDimitry Andric     void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
186a7dea167SDimitry Andric       return Alloc.Allocate(Meta + Data, alignof(void *));
187a7dea167SDimitry Andric     }
188a7dea167SDimitry Andric 
189a7dea167SDimitry Andric     /// Return a pointer to the data.
190a7dea167SDimitry Andric     char *data() { return B.data(); }
191a7dea167SDimitry Andric     /// Return a pointer to the block.
192a7dea167SDimitry Andric     Block *block() { return &B; }
193a7dea167SDimitry Andric 
194a7dea167SDimitry Andric   private:
195a7dea167SDimitry Andric     /// Required metadata - does not actually track pointers.
196a7dea167SDimitry Andric     Block B;
197a7dea167SDimitry Andric   };
198a7dea167SDimitry Andric 
199a7dea167SDimitry Andric   /// Allocator for globals.
200a7dea167SDimitry Andric   PoolAllocTy Allocator;
201a7dea167SDimitry Andric 
202a7dea167SDimitry Andric   /// Global objects.
203a7dea167SDimitry Andric   std::vector<Global *> Globals;
204a7dea167SDimitry Andric   /// Cached global indices.
205a7dea167SDimitry Andric   llvm::DenseMap<const void *, unsigned> GlobalIndices;
206a7dea167SDimitry Andric 
207a7dea167SDimitry Andric   /// Mapping from decls to record metadata.
208a7dea167SDimitry Andric   llvm::DenseMap<const RecordDecl *, Record *> Records;
209a7dea167SDimitry Andric 
210a7dea167SDimitry Andric   /// Dummy parameter to generate pointers from.
211a7dea167SDimitry Andric   llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
212a7dea167SDimitry Andric 
213a7dea167SDimitry Andric   /// Creates a new descriptor.
214a7dea167SDimitry Andric   template <typename... Ts>
215a7dea167SDimitry Andric   Descriptor *allocateDescriptor(Ts &&... Args) {
216a7dea167SDimitry Andric     return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
217a7dea167SDimitry Andric   }
218a7dea167SDimitry Andric 
219a7dea167SDimitry Andric   /// No declaration ID.
220a7dea167SDimitry Andric   static constexpr unsigned NoDeclaration = (unsigned)-1;
221a7dea167SDimitry Andric   /// Last declaration ID.
222a7dea167SDimitry Andric   unsigned LastDeclaration = 0;
223a7dea167SDimitry Andric   /// Current declaration ID.
224a7dea167SDimitry Andric   unsigned CurrentDeclaration = NoDeclaration;
225a7dea167SDimitry Andric 
226a7dea167SDimitry Andric   /// Starts evaluating a declaration.
227*06c3fb27SDimitry Andric   void startDeclaration(const ValueDecl *Decl) {
228a7dea167SDimitry Andric     LastDeclaration += 1;
229a7dea167SDimitry Andric     CurrentDeclaration = LastDeclaration;
230a7dea167SDimitry Andric   }
231a7dea167SDimitry Andric 
232a7dea167SDimitry Andric   /// Ends a global declaration.
233a7dea167SDimitry Andric   void endDeclaration() {
234a7dea167SDimitry Andric     CurrentDeclaration = NoDeclaration;
235a7dea167SDimitry Andric   }
236a7dea167SDimitry Andric 
237a7dea167SDimitry Andric public:
238a7dea167SDimitry Andric   /// Dumps the disassembled bytecode to \c llvm::errs().
239a7dea167SDimitry Andric   void dump() const;
240a7dea167SDimitry Andric   void dump(llvm::raw_ostream &OS) const;
241a7dea167SDimitry Andric };
242a7dea167SDimitry Andric 
243a7dea167SDimitry Andric } // namespace interp
244a7dea167SDimitry Andric } // namespace clang
245a7dea167SDimitry Andric 
246a7dea167SDimitry Andric #endif
247