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