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 
26 namespace clang {
27 class QualType;
28 
29 namespace interp {
30 
31 template <class Emitter> class LocalScope;
32 template <class Emitter> class DestructorScope;
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 template <class Emitter> class ArrayIndexScope;
38 
39 /// Compilation context for expressions.
40 template <class Emitter>
41 class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
42                         public Emitter {
43 protected:
44   // Aliases for types defined in the emitter.
45   using LabelTy = typename Emitter::LabelTy;
46   using AddrTy = typename Emitter::AddrTy;
47 
48   /// Current compilation context.
49   Context &Ctx;
50   /// Program to link to.
51   Program &P;
52 
53 public:
54   /// Initializes the compiler and the backend emitter.
55   template <typename... Tys>
56   ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
57       : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
58 
59   // Expression visitors - result returned on interp stack.
60   bool VisitCastExpr(const CastExpr *E);
61   bool VisitIntegerLiteral(const IntegerLiteral *E);
62   bool VisitFloatingLiteral(const FloatingLiteral *E);
63   bool VisitParenExpr(const ParenExpr *E);
64   bool VisitBinaryOperator(const BinaryOperator *E);
65   bool VisitLogicalBinOp(const BinaryOperator *E);
66   bool VisitPointerArithBinOp(const BinaryOperator *E);
67   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
68   bool VisitCallExpr(const CallExpr *E);
69   bool VisitBuiltinCallExpr(const CallExpr *E);
70   bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E);
71   bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
72   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
73   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
74   bool VisitCXXThisExpr(const CXXThisExpr *E);
75   bool VisitUnaryOperator(const UnaryOperator *E);
76   bool VisitDeclRefExpr(const DeclRefExpr *E);
77   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
78   bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
79   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
80   bool VisitInitListExpr(const InitListExpr *E);
81   bool VisitConstantExpr(const ConstantExpr *E);
82   bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
83   bool VisitMemberExpr(const MemberExpr *E);
84   bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
85   bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
86   bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
87   bool VisitStringLiteral(const StringLiteral *E);
88   bool VisitCharacterLiteral(const CharacterLiteral *E);
89   bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
90   bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);
91   bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
92   bool VisitExprWithCleanups(const ExprWithCleanups *E);
93   bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
94   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
95   bool VisitTypeTraitExpr(const TypeTraitExpr *E);
96   bool VisitLambdaExpr(const LambdaExpr *E);
97   bool VisitPredefinedExpr(const PredefinedExpr *E);
98 
99 protected:
100   bool visitExpr(const Expr *E) override;
101   bool visitDecl(const VarDecl *VD) override;
102 
103 protected:
104   /// Emits scope cleanup instructions.
105   void emitCleanup();
106 
107   /// Returns a record type from a record or pointer type.
108   const RecordType *getRecordTy(QualType Ty);
109 
110   /// Returns a record from a record or pointer type.
111   Record *getRecord(QualType Ty);
112   Record *getRecord(const RecordDecl *RD);
113 
114   // Returns a function for the given FunctionDecl.
115   // If the function does not exist yet, it is compiled.
116   const Function *getFunction(const FunctionDecl *FD);
117 
118   /// Classifies a type.
119   std::optional<PrimType> classify(const Expr *E) const {
120     return E->isGLValue() ? PT_Ptr : classify(E->getType());
121   }
122   std::optional<PrimType> classify(QualType Ty) const {
123     return Ctx.classify(Ty);
124   }
125 
126   /// Classifies a known primitive type
127   PrimType classifyPrim(QualType Ty) const {
128     if (auto T = classify(Ty)) {
129       return *T;
130     }
131     llvm_unreachable("not a primitive type");
132   }
133 
134   /// Evaluates an expression for side effects and discards the result.
135   bool discard(const Expr *E);
136   /// Evaluates an expression and places result on stack.
137   bool visit(const Expr *E);
138   /// Compiles an initializer.
139   bool visitInitializer(const Expr *E);
140   /// Compiles an array initializer.
141   bool visitArrayInitializer(const Expr *Initializer);
142   /// Compiles a record initializer.
143   bool visitRecordInitializer(const Expr *Initializer);
144   /// Creates and initializes a variable from the given decl.
145   bool visitVarDecl(const VarDecl *VD);
146 
147   /// Visits an expression and converts it to a boolean.
148   bool visitBool(const Expr *E);
149 
150   /// Visits an initializer for a local.
151   bool visitLocalInitializer(const Expr *Init, unsigned I) {
152     if (!this->emitGetPtrLocal(I, Init))
153       return false;
154 
155     if (!visitInitializer(Init))
156       return false;
157 
158     return this->emitPopPtr(Init);
159   }
160 
161   /// Visits an initializer for a global.
162   bool visitGlobalInitializer(const Expr *Init, unsigned I) {
163     if (!this->emitGetPtrGlobal(I, Init))
164       return false;
165 
166     if (!visitInitializer(Init))
167       return false;
168 
169     if ((Init->getType()->isArrayType() || Init->getType()->isRecordType()) &&
170         !this->emitCheckGlobalCtor(Init))
171       return false;
172 
173     return this->emitPopPtr(Init);
174   }
175 
176   /// Visits a delegated initializer.
177   bool visitThisInitializer(const Expr *I) {
178     if (!this->emitThis(I))
179       return false;
180 
181     if (!visitInitializer(I))
182       return false;
183 
184     return this->emitPopPtr(I);
185   }
186 
187   bool visitConditional(const AbstractConditionalOperator *E,
188                         llvm::function_ref<bool(const Expr *)> V);
189 
190   /// Creates a local primitive value.
191   unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
192                                   bool IsExtended = false);
193 
194   /// Allocates a space storing a local given its type.
195   std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false);
196 
197 private:
198   friend class VariableScope<Emitter>;
199   friend class LocalScope<Emitter>;
200   friend class DestructorScope<Emitter>;
201   friend class RecordScope<Emitter>;
202   friend class DeclScope<Emitter>;
203   friend class OptionScope<Emitter>;
204   friend class ArrayIndexScope<Emitter>;
205 
206   /// Emits a zero initializer.
207   bool visitZeroInitializer(QualType QT, const Expr *E);
208 
209   enum class DerefKind {
210     /// Value is read and pushed to stack.
211     Read,
212     /// Direct method generates a value which is written. Returns pointer.
213     Write,
214     /// Direct method receives the value, pushes mutated value. Returns pointer.
215     ReadWrite,
216   };
217 
218   /// Method to directly load a value. If the value can be fetched directly,
219   /// the direct handler is called. Otherwise, a pointer is left on the stack
220   /// and the indirect handler is expected to operate on that.
221   bool dereference(const Expr *LV, DerefKind AK,
222                    llvm::function_ref<bool(PrimType)> Direct,
223                    llvm::function_ref<bool(PrimType)> Indirect);
224   bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
225                         DerefKind AK,
226                         llvm::function_ref<bool(PrimType)> Direct,
227                         llvm::function_ref<bool(PrimType)> Indirect);
228   bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
229                       DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
230                       llvm::function_ref<bool(PrimType)> Indirect);
231 
232   /// Emits an APSInt constant.
233   bool emitConst(const llvm::APSInt &Value, const Expr *E);
234   bool emitConst(const llvm::APInt &Value, const Expr *E) {
235     return emitConst(static_cast<llvm::APSInt>(Value), E);
236   }
237 
238   /// Emits an integer constant.
239   template <typename T> bool emitConst(T Value, const Expr *E);
240 
241   /// Returns the CXXRecordDecl for the type of the given expression,
242   /// or nullptr if no such decl exists.
243   const CXXRecordDecl *getRecordDecl(const Expr *E) const {
244     QualType T = E->getType();
245     if (const auto *RD = T->getPointeeCXXRecordDecl())
246       return RD;
247     return T->getAsCXXRecordDecl();
248   }
249 
250   llvm::RoundingMode getRoundingMode(const Expr *E) const {
251     FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts());
252 
253     if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)
254       return llvm::RoundingMode::NearestTiesToEven;
255 
256     return FPO.getRoundingMode();
257   }
258 
259   bool emitRecordDestruction(const Descriptor *Desc);
260   bool emitDerivedToBaseCasts(const RecordType *DerivedType,
261                               const RecordType *BaseType, const Expr *E);
262 
263 protected:
264   /// Variable to storage mapping.
265   llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
266 
267   /// OpaqueValueExpr to location mapping.
268   llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
269 
270   /// Current scope.
271   VariableScope<Emitter> *VarScope = nullptr;
272 
273   /// Current argument index. Needed to emit ArrayInitIndexExpr.
274   std::optional<uint64_t> ArrayIndex;
275 
276   /// Flag indicating if return value is to be discarded.
277   bool DiscardResult = false;
278 };
279 
280 extern template class ByteCodeExprGen<ByteCodeEmitter>;
281 extern template class ByteCodeExprGen<EvalEmitter>;
282 
283 /// Scope chain managing the variable lifetimes.
284 template <class Emitter> class VariableScope {
285 public:
286   VariableScope(ByteCodeExprGen<Emitter> *Ctx)
287       : Ctx(Ctx), Parent(Ctx->VarScope) {
288     Ctx->VarScope = this;
289   }
290 
291   virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
292 
293   void add(const Scope::Local &Local, bool IsExtended) {
294     if (IsExtended)
295       this->addExtended(Local);
296     else
297       this->addLocal(Local);
298   }
299 
300   virtual void addLocal(const Scope::Local &Local) {
301     if (this->Parent)
302       this->Parent->addLocal(Local);
303   }
304 
305   virtual void addExtended(const Scope::Local &Local) {
306     if (this->Parent)
307       this->Parent->addExtended(Local);
308   }
309 
310   virtual void emitDestruction() {}
311   virtual void emitDestructors() {}
312   VariableScope *getParent() const { return Parent; }
313 
314 protected:
315   /// ByteCodeExprGen instance.
316   ByteCodeExprGen<Emitter> *Ctx;
317   /// Link to the parent scope.
318   VariableScope *Parent;
319 };
320 
321 /// Generic scope for local variables.
322 template <class Emitter> class LocalScope : public VariableScope<Emitter> {
323 public:
324   LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
325 
326   /// Emit a Destroy op for this scope.
327   ~LocalScope() override {
328     if (!Idx)
329       return;
330     this->Ctx->emitDestroy(*Idx, SourceInfo{});
331   }
332 
333   /// Overriden to support explicit destruction.
334   void emitDestruction() override {
335     if (!Idx)
336       return;
337     this->emitDestructors();
338     this->Ctx->emitDestroy(*Idx, SourceInfo{});
339     this->Idx = std::nullopt;
340   }
341 
342   void addLocal(const Scope::Local &Local) override {
343     if (!Idx) {
344       Idx = this->Ctx->Descriptors.size();
345       this->Ctx->Descriptors.emplace_back();
346     }
347 
348     this->Ctx->Descriptors[*Idx].emplace_back(Local);
349   }
350 
351   void emitDestructors() override {
352     if (!Idx)
353       return;
354     // Emit destructor calls for local variables of record
355     // type with a destructor.
356     for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
357       if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {
358         this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{});
359         this->Ctx->emitRecordDestruction(Local.Desc);
360       }
361     }
362   }
363 
364   /// Index of the scope in the chain.
365   std::optional<unsigned> Idx;
366 };
367 
368 /// Emits the destructors of the variables of \param OtherScope
369 /// when this scope is destroyed. Does not create a Scope in the bytecode at
370 /// all, this is just a RAII object to emit destructors.
371 template <class Emitter> class DestructorScope final {
372 public:
373   DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {}
374 
375   ~DestructorScope() { OtherScope.emitDestructors(); }
376 
377 private:
378   LocalScope<Emitter> &OtherScope;
379 };
380 
381 /// Like a regular LocalScope, except that the destructors of all local
382 /// variables are automatically emitted when the AutoScope is destroyed.
383 template <class Emitter> class AutoScope : public LocalScope<Emitter> {
384 public:
385   AutoScope(ByteCodeExprGen<Emitter> *Ctx)
386       : LocalScope<Emitter>(Ctx), DS(*this) {}
387 
388 private:
389   DestructorScope<Emitter> DS;
390 };
391 
392 /// Scope for storage declared in a compound statement.
393 template <class Emitter> class BlockScope final : public AutoScope<Emitter> {
394 public:
395   BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
396 
397   void addExtended(const Scope::Local &Local) override {
398     // If we to this point, just add the variable as a normal local
399     // variable. It will be destroyed at the end of the block just
400     // like all others.
401     this->addLocal(Local);
402   }
403 };
404 
405 /// Expression scope which tracks potentially lifetime extended
406 /// temporaries which are hoisted to the parent scope on exit.
407 template <class Emitter> class ExprScope final : public AutoScope<Emitter> {
408 public:
409   ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
410 
411   void addExtended(const Scope::Local &Local) override {
412     if (this->Parent)
413       this->Parent->addLocal(Local);
414   }
415 };
416 
417 template <class Emitter> class ArrayIndexScope final {
418 public:
419   ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
420     OldArrayIndex = Ctx->ArrayIndex;
421     Ctx->ArrayIndex = Index;
422   }
423 
424   ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
425 
426 private:
427   ByteCodeExprGen<Emitter> *Ctx;
428   std::optional<uint64_t> OldArrayIndex;
429 };
430 
431 } // namespace interp
432 } // namespace clang
433 
434 #endif
435