clang  10.0.0svn
ByteCodeExprGen.h
Go to the documentation of this file.
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 "llvm/ADT/Optional.h"
25 
26 namespace clang {
27 class QualType;
28 
29 namespace interp {
30 class Function;
31 class State;
32 
33 template <class Emitter> class LocalScope;
34 template <class Emitter> class RecordScope;
35 template <class Emitter> class VariableScope;
36 template <class Emitter> class DeclScope;
37 template <class Emitter> class OptionScope;
38 
39 /// Compilation context for expressions.
40 template <class Emitter>
41 class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
42  public Emitter {
43 protected:
44  // Emitters for opcodes of various arities.
45  using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &);
48  const SourceInfo &);
49 
50  // Aliases for types defined in the emitter.
51  using LabelTy = typename Emitter::LabelTy;
52  using AddrTy = typename Emitter::AddrTy;
53 
54  // Reference to a function generating the pointer of an initialized object.s
55  using InitFnRef = std::function<bool()>;
56 
57  /// Current compilation context.
59  /// Program to link to.
61 
62 public:
63  /// Initializes the compiler and the backend emitter.
64  template <typename... Tys>
65  ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
66  : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
67 
68  // Expression visitors - result returned on stack.
69  bool VisitCastExpr(const CastExpr *E);
70  bool VisitIntegerLiteral(const IntegerLiteral *E);
71  bool VisitParenExpr(const ParenExpr *E);
72  bool VisitBinaryOperator(const BinaryOperator *E);
73 
74 protected:
75  bool visitExpr(const Expr *E) override;
76  bool visitDecl(const VarDecl *VD) override;
77 
78 protected:
79  /// Emits scope cleanup instructions.
80  void emitCleanup();
81 
82  /// Returns a record type from a record or pointer type.
83  const RecordType *getRecordTy(QualType Ty);
84 
85  /// Returns a record from a record or pointer type.
87  Record *getRecord(const RecordDecl *RD);
88 
89  /// Returns the size int bits of an integer.
90  unsigned getIntWidth(QualType Ty) {
91  auto &ASTContext = Ctx.getASTContext();
92  return ASTContext.getIntWidth(Ty);
93  }
94 
95  /// Returns the value of CHAR_BIT.
96  unsigned getCharBit() const {
97  auto &ASTContext = Ctx.getASTContext();
99  }
100 
101  /// Classifies a type.
103  return E->isGLValue() ? PT_Ptr : classify(E->getType());
104  }
106  return Ctx.classify(Ty);
107  }
108 
109  /// Checks if a pointer needs adjustment.
110  bool needsAdjust(QualType Ty) const {
111  return true;
112  }
113 
114  /// Classifies a known primitive type
115  PrimType classifyPrim(QualType Ty) const {
116  if (auto T = classify(Ty)) {
117  return *T;
118  }
119  llvm_unreachable("not a primitive type");
120  }
121 
122  /// Evaluates an expression for side effects and discards the result.
123  bool discard(const Expr *E);
124  /// Evaluates an expression and places result on stack.
125  bool visit(const Expr *E);
126  /// Compiles an initializer for a local.
127  bool visitInitializer(const Expr *E, InitFnRef GenPtr);
128 
129  /// Visits an expression and converts it to a boolean.
130  bool visitBool(const Expr *E);
131 
132  /// Visits an initializer for a local.
133  bool visitLocalInitializer(const Expr *Init, unsigned I) {
134  return visitInitializer(Init, [this, I, Init] {
135  return this->emitGetPtrLocal(I, Init);
136  });
137  }
138 
139  /// Visits an initializer for a global.
140  bool visitGlobalInitializer(const Expr *Init, unsigned I) {
141  return visitInitializer(Init, [this, I, Init] {
142  return this->emitGetPtrGlobal(I, Init);
143  });
144  }
145 
146  /// Visits a delegated initializer.
147  bool visitThisInitializer(const Expr *I) {
148  return visitInitializer(I, [this, I] { return this->emitThis(I); });
149  }
150 
151  /// Creates a local primitive value.
152  unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
153  bool IsExtended = false);
154 
155  /// Allocates a space storing a local given its type.
157  bool IsExtended = false);
158 
159 private:
160  friend class VariableScope<Emitter>;
161  friend class LocalScope<Emitter>;
162  friend class RecordScope<Emitter>;
163  friend class DeclScope<Emitter>;
164  friend class OptionScope<Emitter>;
165 
166  /// Emits a zero initializer.
167  bool visitZeroInitializer(PrimType T, const Expr *E);
168 
169  enum class DerefKind {
170  /// Value is read and pushed to stack.
171  Read,
172  /// Direct method generates a value which is written. Returns pointer.
173  Write,
174  /// Direct method receives the value, pushes mutated value. Returns pointer.
175  ReadWrite,
176  };
177 
178  /// Method to directly load a value. If the value can be fetched directly,
179  /// the direct handler is called. Otherwise, a pointer is left on the stack
180  /// and the indirect handler is expected to operate on that.
181  bool dereference(const Expr *LV, DerefKind AK,
182  llvm::function_ref<bool(PrimType)> Direct,
183  llvm::function_ref<bool(PrimType)> Indirect);
184  bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
185  DerefKind AK,
186  llvm::function_ref<bool(PrimType)> Direct,
187  llvm::function_ref<bool(PrimType)> Indirect);
188  bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
189  DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
190  llvm::function_ref<bool(PrimType)> Indirect);
191 
192  /// Emits an APInt constant.
193  bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value,
194  const Expr *E);
195 
196  /// Emits an integer constant.
197  template <typename T> bool emitConst(const Expr *E, T Value) {
198  QualType Ty = E->getType();
199  unsigned NumBits = getIntWidth(Ty);
200  APInt WrappedValue(NumBits, Value, std::is_signed<T>::value);
201  return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E);
202  }
203 
204  /// Returns a pointer to a variable declaration.
205  bool getPtrVarDecl(const VarDecl *VD, const Expr *E);
206 
207  /// Returns the index of a global.
208  llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD);
209 
210  /// Emits the initialized pointer.
211  bool emitInitFn() {
212  assert(InitFn && "missing initializer");
213  return (*InitFn)();
214  }
215 
216 protected:
217  /// Variable to storage mapping.
218  llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
219 
220  /// OpaqueValueExpr to location mapping.
221  llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
222 
223  /// Current scope.
225 
226  /// Current argument index.
228 
229  /// Flag indicating if return value is to be discarded.
230  bool DiscardResult = false;
231 
232  /// Expression being initialized.
234 };
235 
236 extern template class ByteCodeExprGen<ByteCodeEmitter>;
237 extern template class ByteCodeExprGen<EvalEmitter>;
238 
239 /// Scope chain managing the variable lifetimes.
240 template <class Emitter> class VariableScope {
241 public:
242  virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
243 
244  void add(const Scope::Local &Local, bool IsExtended) {
245  if (IsExtended)
246  this->addExtended(Local);
247  else
248  this->addLocal(Local);
249  }
250 
251  virtual void addLocal(const Scope::Local &Local) {
252  if (this->Parent)
253  this->Parent->addLocal(Local);
254  }
255 
256  virtual void addExtended(const Scope::Local &Local) {
257  if (this->Parent)
258  this->Parent->addExtended(Local);
259  }
260 
261  virtual void emitDestruction() {}
262 
264 
265 protected:
267  : Ctx(Ctx), Parent(Ctx->VarScope) {
268  Ctx->VarScope = this;
269  }
270 
271  /// ByteCodeExprGen instance.
273  /// Link to the parent scope.
275 };
276 
277 /// Scope for local variables.
278 ///
279 /// When the scope is destroyed, instructions are emitted to tear down
280 /// all variables declared in this scope.
281 template <class Emitter> class LocalScope : public VariableScope<Emitter> {
282 public:
284 
285  ~LocalScope() override { this->emitDestruction(); }
286 
287  void addLocal(const Scope::Local &Local) override {
288  if (!Idx.hasValue()) {
289  Idx = this->Ctx->Descriptors.size();
290  this->Ctx->Descriptors.emplace_back();
291  }
292 
293  this->Ctx->Descriptors[*Idx].emplace_back(Local);
294  }
295 
296  void emitDestruction() override {
297  if (!Idx.hasValue())
298  return;
299  this->Ctx->emitDestroy(*Idx, SourceInfo{});
300  }
301 
302 protected:
303  /// Index of the scope in the chain.
305 };
306 
307 /// Scope for storage declared in a compound statement.
308 template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
309 public:
311 
312  void addExtended(const Scope::Local &Local) override {
313  llvm_unreachable("Cannot create temporaries in full scopes");
314  }
315 };
316 
317 /// Expression scope which tracks potentially lifetime extended
318 /// temporaries which are hoisted to the parent scope on exit.
319 template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
320 public:
322 
323  void addExtended(const Scope::Local &Local) override {
324  this->Parent->addLocal(Local);
325  }
326 };
327 
328 } // namespace interp
329 } // namespace clang
330 
331 #endif
VariableScope * Parent
Link to the parent scope.
unsigned llvm::PointerUnion< const Decl *, const Expr * > DeclTy
Definition: Descriptor.h:26
Scope chain managing the variable lifetimes.
A (possibly-)qualified type.
Definition: Type.h:643
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:192
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
llvm::DenseMap< const ValueDecl *, Scope::Local > Locals
Variable to storage mapping.
ParenExpr - This represents a parethesized expression, e.g.
Definition: Expr.h:1969
bool VisitCastExpr(const CastExpr *E)
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:706
constexpr XRayInstrMask Function
Definition: XRayInstr.h:38
unsigned getCharWidth() const
Definition: TargetInfo.h:382
Represents a variable declaration or definition.
Definition: Decl.h:827
bool visitInitializer(const Expr *E, InitFnRef GenPtr)
Compiles an initializer for a local.
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:81
Holds all information required to evaluate constexpr code in a module.
Definition: Context.h:48
Represents a parameter to a function.
Definition: Decl.h:1600
bool VisitIntegerLiteral(const IntegerLiteral *E)
bool(ByteCodeExprGen::*)(PrimType, const SourceInfo &) UnaryFn
llvm::Optional< PrimType > classify(QualType T)
Classifies an expression.
Definition: Context.cpp:68
Represents a struct/union/class.
Definition: Decl.h:3662
bool visitDecl(const VarDecl *VD) override
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:160
LineState State
bool(ByteCodeExprGen::*)(const SourceInfo &) NullaryFn
bool needsAdjust(QualType Ty) const
Checks if a pointer needs adjustment.
bool visit(const Expr *E)
Evaluates an expression and places result on stack.
llvm::Optional< InitFnRef > InitFn
Expression being initialized.
LocalScope(ByteCodeExprGen< Emitter > *Ctx)
void emitDestruction() override
Structure/Class descriptor.
Definition: Record.h:23
bool isGLValue() const
Definition: Expr.h:261
void addLocal(const Scope::Local &Local) override
bool visitBool(const Expr *E)
Visits an expression and converts it to a boolean.
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:27
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3409
void add(const Scope::Local &Local, bool IsExtended)
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3125
Optional< unsigned > Idx
Index of the scope in the chain.
llvm::DenseMap< const OpaqueValueExpr *, unsigned > OpaqueExprs
OpaqueValueExpr to location mapping.
Expression scope which tracks potentially lifetime extended temporaries which are hoisted to the pare...
Scope for storage declared in a compound statement.
bool VisitBinaryOperator(const BinaryOperator *E)
NodeId Parent
Definition: ASTDiff.cpp:191
ExprScope(ByteCodeExprGen< Emitter > *Ctx)
bool discard(const Expr *E)
Evaluates an expression for side effects and discards the result.
This represents one expression.
Definition: Expr.h:108
Information about a local&#39;s storage.
Definition: Function.h:35
std::function< bool()> InitFnRef
ByteCodeExprGen< Emitter > * Ctx
ByteCodeExprGen instance.
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:68
#define bool
Definition: stdbool.h:15
void addExtended(const Scope::Local &Local) override
QualType getType() const
Definition: Expr.h:137
typename Emitter::AddrTy AddrTy
void emitCleanup()
Emits scope cleanup instructions.
The program contains and links the bytecode for all functions.
Definition: Program.h:43
virtual void addLocal(const Scope::Local &Local)
VariableScope(ByteCodeExprGen< Emitter > *Ctx)
llvm::Optional< PrimType > classify(const Expr *E) const
Classifies a type.
Record * getRecord(QualType Ty)
Returns a record from a record or pointer type.
Scope used to handle temporaries in toplevel variable declarations.
llvm::APInt APInt
Definition: Integral.h:27
bool visitThisInitializer(const Expr *I)
Visits a delegated initializer.
Scope used to handle initialization methods.
Dataflow Directional Tag Classes.
bool DiscardResult
Flag indicating if return value is to be discarded.
unsigned getIntWidth(QualType Ty)
Returns the size int bits of an integer.
void addExtended(const Scope::Local &Local) override
bool(ByteCodeExprGen::*)(PrimType, PrimType, const SourceInfo &) BinaryFn
PrimType classifyPrim(QualType Ty) const
Classifies a known primitive type.
bool visitLocalInitializer(const Expr *Init, unsigned I)
Visits an initializer for a local.
const RecordType * getRecordTy(QualType Ty)
Returns a record type from a record or pointer type.
bool visitExpr(const Expr *E) override
unsigned getIntWidth(QualType T) const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4444
Context & Ctx
Current compilation context.
ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
Initializes the compiler and the backend emitter.
Program & P
Program to link to.
Scope for local variables.
bool VisitParenExpr(const ParenExpr *E)
Compilation context for expressions.
typename Emitter::LabelTy LabelTy
BlockScope(ByteCodeExprGen< Emitter > *Ctx)
VariableScope< Emitter > * VarScope
Current scope.
llvm::Optional< PrimType > classify(QualType Ty) const
bool visitGlobalInitializer(const Expr *Init, unsigned I)
Visits an initializer for a global.
virtual void addExtended(const Scope::Local &Local)
llvm::Optional< uint64_t > ArrayIndex
Current argument index.
unsigned getCharBit() const
Returns the value of CHAR_BIT.
llvm::Optional< unsigned > allocateLocal(DeclTy &&Decl, bool IsExtended=false)
Allocates a space storing a local given its type.
unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable, bool IsExtended=false)
Creates a local primitive value.