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