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
28namespace clang {
29class RecordDecl;
30class Expr;
31class FunctionDecl;
32class Stmt;
33class StringLiteral;
34class VarDecl;
35
36namespace interp {
37class Context;
38class State;
39class Record;
40class Scope;
41
42/// The program contains and links the bytecode for all functions.
43class Program {
44public:
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
130private:
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
211public:
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