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