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 &);
46   using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &);
47   using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType,
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.
58   Context &Ctx;
59   /// Program to link to.
60   Program &P;
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.
86   Record *getRecord(QualType Ty);
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();
98     return ASTContext.getTargetInfo().getCharWidth();
99   }
100 
101   /// Classifies a type.
102   llvm::Optional<PrimType> classify(const Expr *E) const {
103     return E->isGLValue() ? PT_Ptr : classify(E->getType());
104   }
105   llvm::Optional<PrimType> classify(QualType Ty) const {
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.
156   llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
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.
224   VariableScope<Emitter> *VarScope = nullptr;
225 
226   /// Current argument index.
227   llvm::Optional<uint64_t> ArrayIndex;
228 
229   /// Flag indicating if return value is to be discarded.
230   bool DiscardResult = false;
231 
232   /// Expression being initialized.
233   llvm::Optional<InitFnRef> InitFn = {};
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 
263   VariableScope *getParent() { return Parent; }
264 
265 protected:
266   VariableScope(ByteCodeExprGen<Emitter> *Ctx)
267       : Ctx(Ctx), Parent(Ctx->VarScope) {
268     Ctx->VarScope = this;
269   }
270 
271   /// ByteCodeExprGen instance.
272   ByteCodeExprGen<Emitter> *Ctx;
273   /// Link to the parent scope.
274   VariableScope *Parent;
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:
283   LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
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.
304   Optional<unsigned> Idx;
305 };
306 
307 /// Scope for storage declared in a compound statement.
308 template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
309 public:
310   BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
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:
321   ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
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
332