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