1//===--- ByteCodeExprGen.h - Code generator for expressions -----*- 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 the constexpr bytecode compiler.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
14#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
15
16#include "ByteCodeEmitter.h"
17#include "EvalEmitter.h"
18#include "Pointer.h"
19#include "PrimType.h"
20#include "Record.h"
21#include "clang/AST/Decl.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/StmtVisitor.h"
24#include "clang/Basic/TargetInfo.h"
25#include "llvm/ADT/Optional.h"
26
27namespace clang {
28class QualType;
29
30namespace interp {
31class Function;
32class State;
33
34template <class Emitter> class LocalScope;
35template <class Emitter> class RecordScope;
36template <class Emitter> class VariableScope;
37template <class Emitter> class DeclScope;
38template <class Emitter> class OptionScope;
39
40/// Compilation context for expressions.
41template <class Emitter>
42class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
43                        public Emitter {
44protected:
45  // Emitters for opcodes of various arities.
46  using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &);
47  using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &);
48  using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType,
49                                             const SourceInfo &);
50
51  // Aliases for types defined in the emitter.
52  using LabelTy = typename Emitter::LabelTy;
53  using AddrTy = typename Emitter::AddrTy;
54
55  // Reference to a function generating the pointer of an initialized object.s
56  using InitFnRef = std::function<bool()>;
57
58  /// Current compilation context.
59  Context &Ctx;
60  /// Program to link to.
61  Program &P;
62
63public:
64  /// Initializes the compiler and the backend emitter.
65  template <typename... Tys>
66  ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
67      : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
68
69  // Expression visitors - result returned on stack.
70  bool VisitCastExpr(const CastExpr *E);
71  bool VisitIntegerLiteral(const IntegerLiteral *E);
72  bool VisitParenExpr(const ParenExpr *E);
73  bool VisitBinaryOperator(const BinaryOperator *E);
74
75protected:
76  bool visitExpr(const Expr *E) override;
77  bool visitDecl(const VarDecl *VD) override;
78
79protected:
80  /// Emits scope cleanup instructions.
81  void emitCleanup();
82
83  /// Returns a record type from a record or pointer type.
84  const RecordType *getRecordTy(QualType Ty);
85
86  /// Returns a record from a record or pointer type.
87  Record *getRecord(QualType Ty);
88  Record *getRecord(const RecordDecl *RD);
89
90  /// Returns the size int bits of an integer.
91  unsigned getIntWidth(QualType Ty) {
92    auto &ASTContext = Ctx.getASTContext();
93    return ASTContext.getIntWidth(Ty);
94  }
95
96  /// Returns the value of CHAR_BIT.
97  unsigned getCharBit() const {
98    auto &ASTContext = Ctx.getASTContext();
99    return ASTContext.getTargetInfo().getCharWidth();
100  }
101
102  /// Classifies a type.
103  llvm::Optional<PrimType> classify(const Expr *E) const {
104    return E->isGLValue() ? PT_Ptr : classify(E->getType());
105  }
106  llvm::Optional<PrimType> classify(QualType Ty) const {
107    return Ctx.classify(Ty);
108  }
109
110  /// Checks if a pointer needs adjustment.
111  bool needsAdjust(QualType Ty) const {
112    return true;
113  }
114
115  /// Classifies a known primitive type
116  PrimType classifyPrim(QualType Ty) const {
117    if (auto T = classify(Ty)) {
118      return *T;
119    }
120    llvm_unreachable("not a primitive type");
121  }
122
123  /// Evaluates an expression for side effects and discards the result.
124  bool discard(const Expr *E);
125  /// Evaluates an expression and places result on stack.
126  bool visit(const Expr *E);
127  /// Compiles an initializer for a local.
128  bool visitInitializer(const Expr *E, InitFnRef GenPtr);
129
130  /// Visits an expression and converts it to a boolean.
131  bool visitBool(const Expr *E);
132
133  /// Visits an initializer for a local.
134  bool visitLocalInitializer(const Expr *Init, unsigned I) {
135    return visitInitializer(Init, [this, I, Init] {
136      return this->emitGetPtrLocal(I, Init);
137    });
138  }
139
140  /// Visits an initializer for a global.
141  bool visitGlobalInitializer(const Expr *Init, unsigned I) {
142    return visitInitializer(Init, [this, I, Init] {
143      return this->emitGetPtrGlobal(I, Init);
144    });
145  }
146
147  /// Visits a delegated initializer.
148  bool visitThisInitializer(const Expr *I) {
149    return visitInitializer(I, [this, I] { return this->emitThis(I); });
150  }
151
152  /// Creates a local primitive value.
153  unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
154                                  bool IsExtended = false);
155
156  /// Allocates a space storing a local given its type.
157  llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
158                                         bool IsExtended = false);
159
160private:
161  friend class VariableScope<Emitter>;
162  friend class LocalScope<Emitter>;
163  friend class RecordScope<Emitter>;
164  friend class DeclScope<Emitter>;
165  friend class OptionScope<Emitter>;
166
167  /// Emits a zero initializer.
168  bool visitZeroInitializer(PrimType T, const Expr *E);
169
170  enum class DerefKind {
171    /// Value is read and pushed to stack.
172    Read,
173    /// Direct method generates a value which is written. Returns pointer.
174    Write,
175    /// Direct method receives the value, pushes mutated value. Returns pointer.
176    ReadWrite,
177  };
178
179  /// Method to directly load a value. If the value can be fetched directly,
180  /// the direct handler is called. Otherwise, a pointer is left on the stack
181  /// and the indirect handler is expected to operate on that.
182  bool dereference(const Expr *LV, DerefKind AK,
183                   llvm::function_ref<bool(PrimType)> Direct,
184                   llvm::function_ref<bool(PrimType)> Indirect);
185  bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
186                        DerefKind AK,
187                        llvm::function_ref<bool(PrimType)> Direct,
188                        llvm::function_ref<bool(PrimType)> Indirect);
189  bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
190                      DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
191                      llvm::function_ref<bool(PrimType)> Indirect);
192
193  /// Emits an APInt constant.
194  bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value,
195                 const Expr *E);
196
197  /// Emits an integer constant.
198  template <typename T> bool emitConst(const Expr *E, T Value) {
199    QualType Ty = E->getType();
200    unsigned NumBits = getIntWidth(Ty);
201    APInt WrappedValue(NumBits, Value, std::is_signed<T>::value);
202    return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E);
203  }
204
205  /// Returns a pointer to a variable declaration.
206  bool getPtrVarDecl(const VarDecl *VD, const Expr *E);
207
208  /// Returns the index of a global.
209  llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD);
210
211  /// Emits the initialized pointer.
212  bool emitInitFn() {
213    assert(InitFn && "missing initializer");
214    return (*InitFn)();
215  }
216
217protected:
218  /// Variable to storage mapping.
219  llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
220
221  /// OpaqueValueExpr to location mapping.
222  llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
223
224  /// Current scope.
225  VariableScope<Emitter> *VarScope = nullptr;
226
227  /// Current argument index.
228  llvm::Optional<uint64_t> ArrayIndex;
229
230  /// Flag indicating if return value is to be discarded.
231  bool DiscardResult = false;
232
233  /// Expression being initialized.
234  llvm::Optional<InitFnRef> InitFn = {};
235};
236
237extern template class ByteCodeExprGen<ByteCodeEmitter>;
238extern template class ByteCodeExprGen<EvalEmitter>;
239
240/// Scope chain managing the variable lifetimes.
241template <class Emitter> class VariableScope {
242public:
243  virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
244
245  void add(const Scope::Local &Local, bool IsExtended) {
246    if (IsExtended)
247      this->addExtended(Local);
248    else
249      this->addLocal(Local);
250  }
251
252  virtual void addLocal(const Scope::Local &Local) {
253    if (this->Parent)
254      this->Parent->addLocal(Local);
255  }
256
257  virtual void addExtended(const Scope::Local &Local) {
258    if (this->Parent)
259      this->Parent->addExtended(Local);
260  }
261
262  virtual void emitDestruction() {}
263
264  VariableScope *getParent() { return Parent; }
265
266protected:
267  VariableScope(ByteCodeExprGen<Emitter> *Ctx)
268      : Ctx(Ctx), Parent(Ctx->VarScope) {
269    Ctx->VarScope = this;
270  }
271
272  /// ByteCodeExprGen instance.
273  ByteCodeExprGen<Emitter> *Ctx;
274  /// Link to the parent scope.
275  VariableScope *Parent;
276};
277
278/// Scope for local variables.
279///
280/// When the scope is destroyed, instructions are emitted to tear down
281/// all variables declared in this scope.
282template <class Emitter> class LocalScope : public VariableScope<Emitter> {
283public:
284  LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
285
286  ~LocalScope() override { this->emitDestruction(); }
287
288  void addLocal(const Scope::Local &Local) override {
289    if (!Idx.hasValue()) {
290      Idx = this->Ctx->Descriptors.size();
291      this->Ctx->Descriptors.emplace_back();
292    }
293
294    this->Ctx->Descriptors[*Idx].emplace_back(Local);
295  }
296
297  void emitDestruction() override {
298    if (!Idx.hasValue())
299      return;
300    this->Ctx->emitDestroy(*Idx, SourceInfo{});
301  }
302
303protected:
304  /// Index of the scope in the chain.
305  Optional<unsigned> Idx;
306};
307
308/// Scope for storage declared in a compound statement.
309template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
310public:
311  BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
312
313  void addExtended(const Scope::Local &Local) override {
314    llvm_unreachable("Cannot create temporaries in full scopes");
315  }
316};
317
318/// Expression scope which tracks potentially lifetime extended
319/// temporaries which are hoisted to the parent scope on exit.
320template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
321public:
322  ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
323
324  void addExtended(const Scope::Local &Local) override {
325    this->Parent->addLocal(Local);
326  }
327};
328
329} // namespace interp
330} // namespace clang
331
332#endif
333