xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Program.h (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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 Stmt;
33a7dea167SDimitry Andric class StringLiteral;
34a7dea167SDimitry Andric class VarDecl;
35a7dea167SDimitry Andric 
36a7dea167SDimitry Andric namespace interp {
37a7dea167SDimitry Andric class Context;
38a7dea167SDimitry Andric class State;
39a7dea167SDimitry Andric class Record;
40a7dea167SDimitry Andric class Scope;
41a7dea167SDimitry Andric 
42a7dea167SDimitry Andric /// The program contains and links the bytecode for all functions.
43a7dea167SDimitry Andric class Program {
44a7dea167SDimitry Andric public:
45a7dea167SDimitry Andric   Program(Context &Ctx) : Ctx(Ctx) {}
46a7dea167SDimitry Andric 
47*349cc55cSDimitry Andric   /// Marshals a native pointer to an ID for embedding in bytecode.
48*349cc55cSDimitry Andric   unsigned getOrCreateNativePointer(const void *Ptr);
49*349cc55cSDimitry Andric 
50*349cc55cSDimitry Andric   /// Returns the value of a marshalled native pointer.
51*349cc55cSDimitry Andric   const void *getNativePointer(unsigned Idx);
52*349cc55cSDimitry Andric 
53a7dea167SDimitry Andric   /// Emits a string literal among global data.
54a7dea167SDimitry Andric   unsigned createGlobalString(const StringLiteral *S);
55a7dea167SDimitry Andric 
56a7dea167SDimitry Andric   /// Returns a pointer to a global.
57a7dea167SDimitry Andric   Pointer getPtrGlobal(unsigned Idx);
58a7dea167SDimitry Andric 
59a7dea167SDimitry Andric   /// Returns the value of a global.
60a7dea167SDimitry Andric   Block *getGlobal(unsigned Idx) {
61a7dea167SDimitry Andric     assert(Idx < Globals.size());
62a7dea167SDimitry Andric     return Globals[Idx]->block();
63a7dea167SDimitry Andric   }
64a7dea167SDimitry Andric 
65a7dea167SDimitry Andric   /// Finds a global's index.
66a7dea167SDimitry Andric   llvm::Optional<unsigned> getGlobal(const ValueDecl *VD);
67a7dea167SDimitry Andric 
68a7dea167SDimitry Andric   /// Returns or creates a global an creates an index to it.
69a7dea167SDimitry Andric   llvm::Optional<unsigned> getOrCreateGlobal(const ValueDecl *VD);
70a7dea167SDimitry Andric 
71a7dea167SDimitry Andric   /// Returns or creates a dummy value for parameters.
72a7dea167SDimitry Andric   llvm::Optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
73a7dea167SDimitry Andric 
74a7dea167SDimitry Andric   /// Creates a global and returns its index.
75a7dea167SDimitry Andric   llvm::Optional<unsigned> createGlobal(const ValueDecl *VD);
76a7dea167SDimitry Andric 
77a7dea167SDimitry Andric   /// Creates a global from a lifetime-extended temporary.
78a7dea167SDimitry Andric   llvm::Optional<unsigned> createGlobal(const Expr *E);
79a7dea167SDimitry Andric 
80a7dea167SDimitry Andric   /// Creates a new function from a code range.
81a7dea167SDimitry Andric   template <typename... Ts>
82a7dea167SDimitry Andric   Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
83a7dea167SDimitry Andric     auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
84a7dea167SDimitry Andric     Funcs.insert({Def, std::unique_ptr<Function>(Func)});
85a7dea167SDimitry Andric     return Func;
86a7dea167SDimitry Andric   }
87a7dea167SDimitry Andric   /// Creates an anonymous function.
88a7dea167SDimitry Andric   template <typename... Ts>
89a7dea167SDimitry Andric   Function *createFunction(Ts &&... Args) {
90a7dea167SDimitry Andric     auto *Func = new Function(*this, std::forward<Ts>(Args)...);
91a7dea167SDimitry Andric     AnonFuncs.emplace_back(Func);
92a7dea167SDimitry Andric     return Func;
93a7dea167SDimitry Andric   }
94a7dea167SDimitry Andric 
95a7dea167SDimitry Andric   /// Returns a function.
96a7dea167SDimitry Andric   Function *getFunction(const FunctionDecl *F);
97a7dea167SDimitry Andric 
98a7dea167SDimitry Andric   /// Returns a pointer to a function if it exists and can be compiled.
99a7dea167SDimitry Andric   /// If a function couldn't be compiled, an error is returned.
100a7dea167SDimitry Andric   /// If a function was not yet defined, a null pointer is returned.
101a7dea167SDimitry Andric   llvm::Expected<Function *> getOrCreateFunction(const FunctionDecl *F);
102a7dea167SDimitry Andric 
103a7dea167SDimitry Andric   /// Returns a record or creates one if it does not exist.
104a7dea167SDimitry Andric   Record *getOrCreateRecord(const RecordDecl *RD);
105a7dea167SDimitry Andric 
106a7dea167SDimitry Andric   /// Creates a descriptor for a primitive type.
107a7dea167SDimitry Andric   Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
108a7dea167SDimitry Andric                                bool IsConst = false,
109a7dea167SDimitry Andric                                bool IsTemporary = false,
110a7dea167SDimitry Andric                                bool IsMutable = false) {
111a7dea167SDimitry Andric     return allocateDescriptor(D, Type, IsConst, IsTemporary, IsMutable);
112a7dea167SDimitry Andric   }
113a7dea167SDimitry Andric 
114a7dea167SDimitry Andric   /// Creates a descriptor for a composite type.
115a7dea167SDimitry Andric   Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
116a7dea167SDimitry Andric                                bool IsConst = false, bool IsTemporary = false,
117a7dea167SDimitry Andric                                bool IsMutable = false);
118a7dea167SDimitry Andric 
119a7dea167SDimitry Andric   /// Context to manage declaration lifetimes.
120a7dea167SDimitry Andric   class DeclScope {
121a7dea167SDimitry Andric   public:
122a7dea167SDimitry Andric     DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
123a7dea167SDimitry Andric     ~DeclScope() { P.endDeclaration(); }
124a7dea167SDimitry Andric 
125a7dea167SDimitry Andric   private:
126a7dea167SDimitry Andric     Program &P;
127a7dea167SDimitry Andric   };
128a7dea167SDimitry Andric 
129a7dea167SDimitry Andric   /// Returns the current declaration ID.
130a7dea167SDimitry Andric   llvm::Optional<unsigned> getCurrentDecl() const {
131a7dea167SDimitry Andric     if (CurrentDeclaration == NoDeclaration)
132a7dea167SDimitry Andric       return llvm::Optional<unsigned>{};
133a7dea167SDimitry Andric     return LastDeclaration;
134a7dea167SDimitry Andric   }
135a7dea167SDimitry Andric 
136a7dea167SDimitry Andric private:
137a7dea167SDimitry Andric   friend class DeclScope;
138a7dea167SDimitry Andric 
139a7dea167SDimitry Andric   llvm::Optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
140a7dea167SDimitry Andric                                         bool IsStatic, bool IsExtern);
141a7dea167SDimitry Andric 
142a7dea167SDimitry Andric   /// Reference to the VM context.
143a7dea167SDimitry Andric   Context &Ctx;
144a7dea167SDimitry Andric   /// Mapping from decls to cached bytecode functions.
145a7dea167SDimitry Andric   llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
146a7dea167SDimitry Andric   /// List of anonymous functions.
147a7dea167SDimitry Andric   std::vector<std::unique_ptr<Function>> AnonFuncs;
148a7dea167SDimitry Andric 
149a7dea167SDimitry Andric   /// Function relocation locations.
150a7dea167SDimitry Andric   llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
151a7dea167SDimitry Andric 
152*349cc55cSDimitry Andric   /// Native pointers referenced by bytecode.
153*349cc55cSDimitry Andric   std::vector<const void *> NativePointers;
154*349cc55cSDimitry Andric   /// Cached native pointer indices.
155*349cc55cSDimitry Andric   llvm::DenseMap<const void *, unsigned> NativePointerIndices;
156*349cc55cSDimitry Andric 
157a7dea167SDimitry Andric   /// Custom allocator for global storage.
158a7dea167SDimitry Andric   using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
159a7dea167SDimitry Andric 
160a7dea167SDimitry Andric   /// Descriptor + storage for a global object.
161a7dea167SDimitry Andric   ///
162a7dea167SDimitry Andric   /// Global objects never go out of scope, thus they do not track pointers.
163a7dea167SDimitry Andric   class Global {
164a7dea167SDimitry Andric   public:
165a7dea167SDimitry Andric     /// Create a global descriptor for string literals.
166a7dea167SDimitry Andric     template <typename... Tys>
167a7dea167SDimitry Andric     Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
168a7dea167SDimitry Andric 
169a7dea167SDimitry Andric     /// Allocates the global in the pool, reserving storate for data.
170a7dea167SDimitry Andric     void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
171a7dea167SDimitry Andric       return Alloc.Allocate(Meta + Data, alignof(void *));
172a7dea167SDimitry Andric     }
173a7dea167SDimitry Andric 
174a7dea167SDimitry Andric     /// Return a pointer to the data.
175a7dea167SDimitry Andric     char *data() { return B.data(); }
176a7dea167SDimitry Andric     /// Return a pointer to the block.
177a7dea167SDimitry Andric     Block *block() { return &B; }
178a7dea167SDimitry Andric 
179a7dea167SDimitry Andric   private:
180a7dea167SDimitry Andric     /// Required metadata - does not actually track pointers.
181a7dea167SDimitry Andric     Block B;
182a7dea167SDimitry Andric   };
183a7dea167SDimitry Andric 
184a7dea167SDimitry Andric   /// Allocator for globals.
185a7dea167SDimitry Andric   PoolAllocTy Allocator;
186a7dea167SDimitry Andric 
187a7dea167SDimitry Andric   /// Global objects.
188a7dea167SDimitry Andric   std::vector<Global *> Globals;
189a7dea167SDimitry Andric   /// Cached global indices.
190a7dea167SDimitry Andric   llvm::DenseMap<const void *, unsigned> GlobalIndices;
191a7dea167SDimitry Andric 
192a7dea167SDimitry Andric   /// Mapping from decls to record metadata.
193a7dea167SDimitry Andric   llvm::DenseMap<const RecordDecl *, Record *> Records;
194a7dea167SDimitry Andric 
195a7dea167SDimitry Andric   /// Dummy parameter to generate pointers from.
196a7dea167SDimitry Andric   llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
197a7dea167SDimitry Andric 
198a7dea167SDimitry Andric   /// Creates a new descriptor.
199a7dea167SDimitry Andric   template <typename... Ts>
200a7dea167SDimitry Andric   Descriptor *allocateDescriptor(Ts &&... Args) {
201a7dea167SDimitry Andric     return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
202a7dea167SDimitry Andric   }
203a7dea167SDimitry Andric 
204a7dea167SDimitry Andric   /// No declaration ID.
205a7dea167SDimitry Andric   static constexpr unsigned NoDeclaration = (unsigned)-1;
206a7dea167SDimitry Andric   /// Last declaration ID.
207a7dea167SDimitry Andric   unsigned LastDeclaration = 0;
208a7dea167SDimitry Andric   /// Current declaration ID.
209a7dea167SDimitry Andric   unsigned CurrentDeclaration = NoDeclaration;
210a7dea167SDimitry Andric 
211a7dea167SDimitry Andric   /// Starts evaluating a declaration.
212a7dea167SDimitry Andric   void startDeclaration(const VarDecl *Decl) {
213a7dea167SDimitry Andric     LastDeclaration += 1;
214a7dea167SDimitry Andric     CurrentDeclaration = LastDeclaration;
215a7dea167SDimitry Andric   }
216a7dea167SDimitry Andric 
217a7dea167SDimitry Andric   /// Ends a global declaration.
218a7dea167SDimitry Andric   void endDeclaration() {
219a7dea167SDimitry Andric     CurrentDeclaration = NoDeclaration;
220a7dea167SDimitry Andric   }
221a7dea167SDimitry Andric 
222a7dea167SDimitry Andric public:
223a7dea167SDimitry Andric   /// Dumps the disassembled bytecode to \c llvm::errs().
224a7dea167SDimitry Andric   void dump() const;
225a7dea167SDimitry Andric   void dump(llvm::raw_ostream &OS) const;
226a7dea167SDimitry Andric };
227a7dea167SDimitry Andric 
228a7dea167SDimitry Andric } // namespace interp
229a7dea167SDimitry Andric } // namespace clang
230a7dea167SDimitry Andric 
231a7dea167SDimitry Andric #endif
232