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"
24ec727ea7Spatrick #include "clang/Basic/TargetInfo.h"
25e5dd7070Spatrick 
26e5dd7070Spatrick namespace clang {
27e5dd7070Spatrick class QualType;
28e5dd7070Spatrick 
29e5dd7070Spatrick namespace interp {
30e5dd7070Spatrick 
31e5dd7070Spatrick template <class Emitter> class LocalScope;
32e5dd7070Spatrick template <class Emitter> class RecordScope;
33e5dd7070Spatrick template <class Emitter> class VariableScope;
34e5dd7070Spatrick template <class Emitter> class DeclScope;
35e5dd7070Spatrick template <class Emitter> class OptionScope;
36*12c85518Srobert template <class Emitter> class ArrayIndexScope;
37e5dd7070Spatrick 
38e5dd7070Spatrick /// Compilation context for expressions.
39e5dd7070Spatrick template <class Emitter>
40e5dd7070Spatrick class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
41e5dd7070Spatrick                         public Emitter {
42e5dd7070Spatrick protected:
43e5dd7070Spatrick   // Aliases for types defined in the emitter.
44e5dd7070Spatrick   using LabelTy = typename Emitter::LabelTy;
45e5dd7070Spatrick   using AddrTy = typename Emitter::AddrTy;
46e5dd7070Spatrick 
47e5dd7070Spatrick   /// Current compilation context.
48e5dd7070Spatrick   Context &Ctx;
49e5dd7070Spatrick   /// Program to link to.
50e5dd7070Spatrick   Program &P;
51e5dd7070Spatrick 
52e5dd7070Spatrick public:
53e5dd7070Spatrick   /// Initializes the compiler and the backend emitter.
54e5dd7070Spatrick   template <typename... Tys>
ByteCodeExprGen(Context & Ctx,Program & P,Tys &&...Args)55e5dd7070Spatrick   ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
56e5dd7070Spatrick       : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
57e5dd7070Spatrick 
58*12c85518Srobert   // Expression visitors - result returned on interp stack.
59e5dd7070Spatrick   bool VisitCastExpr(const CastExpr *E);
60e5dd7070Spatrick   bool VisitIntegerLiteral(const IntegerLiteral *E);
61e5dd7070Spatrick   bool VisitParenExpr(const ParenExpr *E);
62e5dd7070Spatrick   bool VisitBinaryOperator(const BinaryOperator *E);
63*12c85518Srobert   bool VisitPointerArithBinOp(const BinaryOperator *E);
64*12c85518Srobert   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
65*12c85518Srobert   bool VisitCallExpr(const CallExpr *E);
66*12c85518Srobert   bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E);
67*12c85518Srobert   bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
68*12c85518Srobert   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
69*12c85518Srobert   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
70*12c85518Srobert   bool VisitCXXThisExpr(const CXXThisExpr *E);
71*12c85518Srobert   bool VisitUnaryOperator(const UnaryOperator *E);
72*12c85518Srobert   bool VisitDeclRefExpr(const DeclRefExpr *E);
73*12c85518Srobert   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
74*12c85518Srobert   bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
75*12c85518Srobert   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
76*12c85518Srobert   bool VisitInitListExpr(const InitListExpr *E);
77*12c85518Srobert   bool VisitConstantExpr(const ConstantExpr *E);
78*12c85518Srobert   bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
79*12c85518Srobert   bool VisitMemberExpr(const MemberExpr *E);
80*12c85518Srobert   bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
81*12c85518Srobert   bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
82*12c85518Srobert   bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
83*12c85518Srobert   bool VisitStringLiteral(const StringLiteral *E);
84*12c85518Srobert   bool VisitCharacterLiteral(const CharacterLiteral *E);
85*12c85518Srobert   bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
86e5dd7070Spatrick 
87e5dd7070Spatrick protected:
88e5dd7070Spatrick   bool visitExpr(const Expr *E) override;
89e5dd7070Spatrick   bool visitDecl(const VarDecl *VD) override;
90e5dd7070Spatrick 
91e5dd7070Spatrick protected:
92e5dd7070Spatrick   /// Emits scope cleanup instructions.
93e5dd7070Spatrick   void emitCleanup();
94e5dd7070Spatrick 
95e5dd7070Spatrick   /// Returns a record type from a record or pointer type.
96e5dd7070Spatrick   const RecordType *getRecordTy(QualType Ty);
97e5dd7070Spatrick 
98e5dd7070Spatrick   /// Returns a record from a record or pointer type.
99e5dd7070Spatrick   Record *getRecord(QualType Ty);
100e5dd7070Spatrick   Record *getRecord(const RecordDecl *RD);
101e5dd7070Spatrick 
102*12c85518Srobert   // Returns a function for the given FunctionDecl.
103*12c85518Srobert   // If the function does not exist yet, it is compiled.
104*12c85518Srobert   const Function *getFunction(const FunctionDecl *FD);
105e5dd7070Spatrick 
106e5dd7070Spatrick   /// Classifies a type.
classify(const Expr * E)107*12c85518Srobert   std::optional<PrimType> classify(const Expr *E) const {
108e5dd7070Spatrick     return E->isGLValue() ? PT_Ptr : classify(E->getType());
109e5dd7070Spatrick   }
classify(QualType Ty)110*12c85518Srobert   std::optional<PrimType> classify(QualType Ty) const {
111e5dd7070Spatrick     return Ctx.classify(Ty);
112e5dd7070Spatrick   }
113e5dd7070Spatrick 
114e5dd7070Spatrick   /// Classifies a known primitive type
classifyPrim(QualType Ty)115e5dd7070Spatrick   PrimType classifyPrim(QualType Ty) const {
116e5dd7070Spatrick     if (auto T = classify(Ty)) {
117e5dd7070Spatrick       return *T;
118e5dd7070Spatrick     }
119e5dd7070Spatrick     llvm_unreachable("not a primitive type");
120e5dd7070Spatrick   }
121e5dd7070Spatrick 
122e5dd7070Spatrick   /// Evaluates an expression for side effects and discards the result.
123e5dd7070Spatrick   bool discard(const Expr *E);
124e5dd7070Spatrick   /// Evaluates an expression and places result on stack.
125e5dd7070Spatrick   bool visit(const Expr *E);
126*12c85518Srobert   /// Compiles an initializer.
127*12c85518Srobert   bool visitInitializer(const Expr *E);
128*12c85518Srobert   /// Compiles an array initializer.
129*12c85518Srobert   bool visitArrayInitializer(const Expr *Initializer);
130*12c85518Srobert   /// Compiles a record initializer.
131*12c85518Srobert   bool visitRecordInitializer(const Expr *Initializer);
132*12c85518Srobert   /// Creates and initializes a variable from the given decl.
133*12c85518Srobert   bool visitVarDecl(const VarDecl *VD);
134e5dd7070Spatrick 
135e5dd7070Spatrick   /// Visits an expression and converts it to a boolean.
136e5dd7070Spatrick   bool visitBool(const Expr *E);
137e5dd7070Spatrick 
138e5dd7070Spatrick   /// Visits an initializer for a local.
visitLocalInitializer(const Expr * Init,unsigned I)139e5dd7070Spatrick   bool visitLocalInitializer(const Expr *Init, unsigned I) {
140*12c85518Srobert     if (!this->emitGetPtrLocal(I, Init))
141*12c85518Srobert       return false;
142*12c85518Srobert 
143*12c85518Srobert     if (!visitInitializer(Init))
144*12c85518Srobert       return false;
145*12c85518Srobert 
146*12c85518Srobert     return this->emitPopPtr(Init);
147e5dd7070Spatrick   }
148e5dd7070Spatrick 
149e5dd7070Spatrick   /// Visits an initializer for a global.
visitGlobalInitializer(const Expr * Init,unsigned I)150e5dd7070Spatrick   bool visitGlobalInitializer(const Expr *Init, unsigned I) {
151*12c85518Srobert     if (!this->emitGetPtrGlobal(I, Init))
152*12c85518Srobert       return false;
153*12c85518Srobert 
154*12c85518Srobert     if (!visitInitializer(Init))
155*12c85518Srobert       return false;
156*12c85518Srobert 
157*12c85518Srobert     return this->emitPopPtr(Init);
158e5dd7070Spatrick   }
159e5dd7070Spatrick 
160e5dd7070Spatrick   /// Visits a delegated initializer.
visitThisInitializer(const Expr * I)161e5dd7070Spatrick   bool visitThisInitializer(const Expr *I) {
162*12c85518Srobert     if (!this->emitThis(I))
163*12c85518Srobert       return false;
164*12c85518Srobert 
165*12c85518Srobert     if (!visitInitializer(I))
166*12c85518Srobert       return false;
167*12c85518Srobert 
168*12c85518Srobert     return this->emitPopPtr(I);
169e5dd7070Spatrick   }
170e5dd7070Spatrick 
171e5dd7070Spatrick   /// Creates a local primitive value.
172e5dd7070Spatrick   unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
173e5dd7070Spatrick                                   bool IsExtended = false);
174e5dd7070Spatrick 
175e5dd7070Spatrick   /// Allocates a space storing a local given its type.
176*12c85518Srobert   std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false);
177e5dd7070Spatrick 
178e5dd7070Spatrick private:
179e5dd7070Spatrick   friend class VariableScope<Emitter>;
180e5dd7070Spatrick   friend class LocalScope<Emitter>;
181e5dd7070Spatrick   friend class RecordScope<Emitter>;
182e5dd7070Spatrick   friend class DeclScope<Emitter>;
183e5dd7070Spatrick   friend class OptionScope<Emitter>;
184*12c85518Srobert   friend class ArrayIndexScope<Emitter>;
185e5dd7070Spatrick 
186e5dd7070Spatrick   /// Emits a zero initializer.
187e5dd7070Spatrick   bool visitZeroInitializer(PrimType T, const Expr *E);
188e5dd7070Spatrick 
189e5dd7070Spatrick   enum class DerefKind {
190e5dd7070Spatrick     /// Value is read and pushed to stack.
191e5dd7070Spatrick     Read,
192e5dd7070Spatrick     /// Direct method generates a value which is written. Returns pointer.
193e5dd7070Spatrick     Write,
194e5dd7070Spatrick     /// Direct method receives the value, pushes mutated value. Returns pointer.
195e5dd7070Spatrick     ReadWrite,
196e5dd7070Spatrick   };
197e5dd7070Spatrick 
198e5dd7070Spatrick   /// Method to directly load a value. If the value can be fetched directly,
199e5dd7070Spatrick   /// the direct handler is called. Otherwise, a pointer is left on the stack
200e5dd7070Spatrick   /// and the indirect handler is expected to operate on that.
201e5dd7070Spatrick   bool dereference(const Expr *LV, DerefKind AK,
202e5dd7070Spatrick                    llvm::function_ref<bool(PrimType)> Direct,
203e5dd7070Spatrick                    llvm::function_ref<bool(PrimType)> Indirect);
204e5dd7070Spatrick   bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
205e5dd7070Spatrick                         DerefKind AK,
206e5dd7070Spatrick                         llvm::function_ref<bool(PrimType)> Direct,
207e5dd7070Spatrick                         llvm::function_ref<bool(PrimType)> Indirect);
208e5dd7070Spatrick   bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
209e5dd7070Spatrick                       DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
210e5dd7070Spatrick                       llvm::function_ref<bool(PrimType)> Indirect);
211e5dd7070Spatrick 
212*12c85518Srobert   /// Emits an APSInt constant.
213*12c85518Srobert   bool emitConst(const APSInt &Value, const Expr *E);
emitConst(const APInt & Value,const Expr * E)214*12c85518Srobert   bool emitConst(const APInt &Value, const Expr *E) {
215*12c85518Srobert     return emitConst(static_cast<APSInt>(Value), E);
216e5dd7070Spatrick   }
217e5dd7070Spatrick 
218*12c85518Srobert   /// Emits an integer constant.
219*12c85518Srobert   template <typename T> bool emitConst(T Value, const Expr *E);
220e5dd7070Spatrick 
221*12c85518Srobert   /// Returns the CXXRecordDecl for the type of the given expression,
222*12c85518Srobert   /// or nullptr if no such decl exists.
getRecordDecl(const Expr * E)223*12c85518Srobert   const CXXRecordDecl *getRecordDecl(const Expr *E) const {
224*12c85518Srobert     QualType T = E->getType();
225*12c85518Srobert     if (const auto *RD = T->getPointeeCXXRecordDecl())
226*12c85518Srobert       return RD;
227*12c85518Srobert     return T->getAsCXXRecordDecl();
228*12c85518Srobert   }
229e5dd7070Spatrick 
230*12c85518Srobert   /// Returns whether we should create a global variable for the
231*12c85518Srobert   /// given VarDecl.
shouldBeGloballyIndexed(const VarDecl * VD)232*12c85518Srobert   bool shouldBeGloballyIndexed(const VarDecl *VD) const {
233*12c85518Srobert     return VD->hasGlobalStorage() || VD->isConstexpr();
234e5dd7070Spatrick   }
235e5dd7070Spatrick 
236e5dd7070Spatrick protected:
237e5dd7070Spatrick   /// Variable to storage mapping.
238e5dd7070Spatrick   llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
239e5dd7070Spatrick 
240e5dd7070Spatrick   /// OpaqueValueExpr to location mapping.
241e5dd7070Spatrick   llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
242e5dd7070Spatrick 
243e5dd7070Spatrick   /// Current scope.
244e5dd7070Spatrick   VariableScope<Emitter> *VarScope = nullptr;
245e5dd7070Spatrick 
246*12c85518Srobert   /// Current argument index. Needed to emit ArrayInitIndexExpr.
247*12c85518Srobert   std::optional<uint64_t> ArrayIndex;
248e5dd7070Spatrick 
249e5dd7070Spatrick   /// Flag indicating if return value is to be discarded.
250e5dd7070Spatrick   bool DiscardResult = false;
251e5dd7070Spatrick };
252e5dd7070Spatrick 
253e5dd7070Spatrick extern template class ByteCodeExprGen<ByteCodeEmitter>;
254e5dd7070Spatrick extern template class ByteCodeExprGen<EvalEmitter>;
255e5dd7070Spatrick 
256e5dd7070Spatrick /// Scope chain managing the variable lifetimes.
257e5dd7070Spatrick template <class Emitter> class VariableScope {
258e5dd7070Spatrick public:
VariableScope(ByteCodeExprGen<Emitter> * Ctx)259*12c85518Srobert   VariableScope(ByteCodeExprGen<Emitter> *Ctx)
260*12c85518Srobert       : Ctx(Ctx), Parent(Ctx->VarScope) {
261*12c85518Srobert     Ctx->VarScope = this;
262*12c85518Srobert   }
263*12c85518Srobert 
~VariableScope()264e5dd7070Spatrick   virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
265e5dd7070Spatrick 
add(const Scope::Local & Local,bool IsExtended)266e5dd7070Spatrick   void add(const Scope::Local &Local, bool IsExtended) {
267e5dd7070Spatrick     if (IsExtended)
268e5dd7070Spatrick       this->addExtended(Local);
269e5dd7070Spatrick     else
270e5dd7070Spatrick       this->addLocal(Local);
271e5dd7070Spatrick   }
272e5dd7070Spatrick 
addLocal(const Scope::Local & Local)273e5dd7070Spatrick   virtual void addLocal(const Scope::Local &Local) {
274e5dd7070Spatrick     if (this->Parent)
275e5dd7070Spatrick       this->Parent->addLocal(Local);
276e5dd7070Spatrick   }
277e5dd7070Spatrick 
addExtended(const Scope::Local & Local)278e5dd7070Spatrick   virtual void addExtended(const Scope::Local &Local) {
279e5dd7070Spatrick     if (this->Parent)
280e5dd7070Spatrick       this->Parent->addExtended(Local);
281e5dd7070Spatrick   }
282e5dd7070Spatrick 
emitDestruction()283e5dd7070Spatrick   virtual void emitDestruction() {}
284e5dd7070Spatrick 
getParent()285e5dd7070Spatrick   VariableScope *getParent() { return Parent; }
286e5dd7070Spatrick 
287e5dd7070Spatrick protected:
288e5dd7070Spatrick   /// ByteCodeExprGen instance.
289e5dd7070Spatrick   ByteCodeExprGen<Emitter> *Ctx;
290e5dd7070Spatrick   /// Link to the parent scope.
291e5dd7070Spatrick   VariableScope *Parent;
292e5dd7070Spatrick };
293e5dd7070Spatrick 
294e5dd7070Spatrick /// Scope for local variables.
295e5dd7070Spatrick ///
296e5dd7070Spatrick /// When the scope is destroyed, instructions are emitted to tear down
297e5dd7070Spatrick /// all variables declared in this scope.
298e5dd7070Spatrick template <class Emitter> class LocalScope : public VariableScope<Emitter> {
299e5dd7070Spatrick public:
LocalScope(ByteCodeExprGen<Emitter> * Ctx)300e5dd7070Spatrick   LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
301e5dd7070Spatrick 
~LocalScope()302e5dd7070Spatrick   ~LocalScope() override { this->emitDestruction(); }
303e5dd7070Spatrick 
addLocal(const Scope::Local & Local)304e5dd7070Spatrick   void addLocal(const Scope::Local &Local) override {
305*12c85518Srobert     if (!Idx) {
306e5dd7070Spatrick       Idx = this->Ctx->Descriptors.size();
307e5dd7070Spatrick       this->Ctx->Descriptors.emplace_back();
308e5dd7070Spatrick     }
309e5dd7070Spatrick 
310e5dd7070Spatrick     this->Ctx->Descriptors[*Idx].emplace_back(Local);
311e5dd7070Spatrick   }
312e5dd7070Spatrick 
emitDestruction()313e5dd7070Spatrick   void emitDestruction() override {
314*12c85518Srobert     if (!Idx)
315e5dd7070Spatrick       return;
316e5dd7070Spatrick     this->Ctx->emitDestroy(*Idx, SourceInfo{});
317e5dd7070Spatrick   }
318e5dd7070Spatrick 
319e5dd7070Spatrick protected:
320e5dd7070Spatrick   /// Index of the scope in the chain.
321*12c85518Srobert   std::optional<unsigned> Idx;
322e5dd7070Spatrick };
323e5dd7070Spatrick 
324e5dd7070Spatrick /// Scope for storage declared in a compound statement.
325e5dd7070Spatrick template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
326e5dd7070Spatrick public:
BlockScope(ByteCodeExprGen<Emitter> * Ctx)327e5dd7070Spatrick   BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
328e5dd7070Spatrick 
addExtended(const Scope::Local & Local)329e5dd7070Spatrick   void addExtended(const Scope::Local &Local) override {
330e5dd7070Spatrick     llvm_unreachable("Cannot create temporaries in full scopes");
331e5dd7070Spatrick   }
332e5dd7070Spatrick };
333e5dd7070Spatrick 
334e5dd7070Spatrick /// Expression scope which tracks potentially lifetime extended
335e5dd7070Spatrick /// temporaries which are hoisted to the parent scope on exit.
336e5dd7070Spatrick template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
337e5dd7070Spatrick public:
ExprScope(ByteCodeExprGen<Emitter> * Ctx)338e5dd7070Spatrick   ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
339e5dd7070Spatrick 
addExtended(const Scope::Local & Local)340e5dd7070Spatrick   void addExtended(const Scope::Local &Local) override {
341*12c85518Srobert     assert(this->Parent);
342e5dd7070Spatrick     this->Parent->addLocal(Local);
343e5dd7070Spatrick   }
344e5dd7070Spatrick };
345e5dd7070Spatrick 
346*12c85518Srobert template <class Emitter> class ArrayIndexScope final {
347*12c85518Srobert public:
ArrayIndexScope(ByteCodeExprGen<Emitter> * Ctx,uint64_t Index)348*12c85518Srobert   ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
349*12c85518Srobert     OldArrayIndex = Ctx->ArrayIndex;
350*12c85518Srobert     Ctx->ArrayIndex = Index;
351*12c85518Srobert   }
352*12c85518Srobert 
~ArrayIndexScope()353*12c85518Srobert   ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
354*12c85518Srobert 
355*12c85518Srobert private:
356*12c85518Srobert   ByteCodeExprGen<Emitter> *Ctx;
357*12c85518Srobert   std::optional<uint64_t> OldArrayIndex;
358*12c85518Srobert };
359*12c85518Srobert 
360e5dd7070Spatrick } // namespace interp
361e5dd7070Spatrick } // namespace clang
362e5dd7070Spatrick 
363e5dd7070Spatrick #endif
364