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 
27 namespace clang {
28 class QualType;
29 
30 namespace interp {
31 class Function;
32 class State;
33 
34 template <class Emitter> class LocalScope;
35 template <class Emitter> class RecordScope;
36 template <class Emitter> class VariableScope;
37 template <class Emitter> class DeclScope;
38 template <class Emitter> class OptionScope;
39 
40 /// Compilation context for expressions.
41 template <class Emitter>
42 class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
43                         public Emitter {
44 protected:
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 
63 public:
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 
75 protected:
76   bool visitExpr(const Expr *E) override;
77   bool visitDecl(const VarDecl *VD) override;
78 
79 protected:
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 
160 private:
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 
217 protected:
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 
237 extern template class ByteCodeExprGen<ByteCodeEmitter>;
238 extern template class ByteCodeExprGen<EvalEmitter>;
239 
240 /// Scope chain managing the variable lifetimes.
241 template <class Emitter> class VariableScope {
242 public:
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 
266 protected:
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.
282 template <class Emitter> class LocalScope : public VariableScope<Emitter> {
283 public:
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 
303 protected:
304   /// Index of the scope in the chain.
305   Optional<unsigned> Idx;
306 };
307 
308 /// Scope for storage declared in a compound statement.
309 template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
310 public:
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.
320 template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
321 public:
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