xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.h (revision f81cdf24ba5436367377f7c8e8f51f6df2a75ca7)
1 //===--- EvalEmitter.h - Instruction emitter for the VM ---------*- 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 instruction emitters.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_AST_INTERP_EVALEMITTER_H
14 #define LLVM_CLANG_AST_INTERP_EVALEMITTER_H
15 
16 #include "ByteCodeGenError.h"
17 #include "Context.h"
18 #include "InterpStack.h"
19 #include "InterpState.h"
20 #include "PrimType.h"
21 #include "Program.h"
22 #include "Source.h"
23 #include "llvm/Support/Error.h"
24 
25 namespace clang {
26 namespace interp {
27 class Context;
28 class Function;
29 class InterpState;
30 class Program;
31 class SourceInfo;
32 enum Opcode : uint32_t;
33 
34 /// An emitter which evaluates opcodes as they are emitted.
35 class EvalEmitter : public SourceMapper {
36 public:
37   using LabelTy = uint32_t;
38   using AddrTy = uintptr_t;
39   using Local = Scope::Local;
40 
41   llvm::Expected<bool> interpretExpr(const Expr *E);
42   llvm::Expected<bool> interpretDecl(const VarDecl *VD);
43 
44 protected:
45   EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk,
46               APValue &Result);
47 
48   virtual ~EvalEmitter() {}
49 
50   /// Define a label.
51   void emitLabel(LabelTy Label);
52   /// Create a label.
53   LabelTy getLabel();
54 
55   /// Methods implemented by the compiler.
56   virtual bool visitExpr(const Expr *E) = 0;
57   virtual bool visitDecl(const VarDecl *VD) = 0;
58 
59   bool bail(const Stmt *S) { return bail(S->getBeginLoc()); }
60   bool bail(const Decl *D) { return bail(D->getBeginLoc()); }
61   bool bail(const SourceLocation &Loc);
62 
63   /// Emits jumps.
64   bool jumpTrue(const LabelTy &Label);
65   bool jumpFalse(const LabelTy &Label);
66   bool jump(const LabelTy &Label);
67   bool fallthrough(const LabelTy &Label);
68 
69   /// Callback for registering a local.
70   Local createLocal(Descriptor *D);
71 
72   /// Returns the source location of the current opcode.
73   SourceInfo getSource(const Function *F, CodePtr PC) const override {
74     return (F && F->hasBody()) ? F->getSource(PC) : CurrentSource;
75   }
76 
77   /// Parameter indices.
78   llvm::DenseMap<const ParmVarDecl *, unsigned> Params;
79   /// Lambda captures.
80   /// Map from Decl* to [Offset, IsReference] pair.
81   llvm::DenseMap<const ValueDecl *, std::pair<unsigned, bool>> LambdaCaptures;
82   unsigned LambdaThisCapture;
83   /// Local descriptors.
84   llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
85 
86 private:
87   /// Current compilation context.
88   Context &Ctx;
89   /// Current program.
90   Program &P;
91   /// Callee evaluation state.
92   InterpState S;
93   /// Location to write the result to.
94   APValue &Result;
95 
96   /// Temporaries which require storage.
97   llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
98 
99   Block *getLocal(unsigned Index) const {
100     auto It = Locals.find(Index);
101     assert(It != Locals.end() && "Missing local variable");
102     return reinterpret_cast<Block *>(It->second.get());
103   }
104 
105   // The emitter always tracks the current instruction and sets OpPC to a token
106   // value which is mapped to the location of the opcode being evaluated.
107   CodePtr OpPC;
108   /// Location of a failure.
109   std::optional<SourceLocation> BailLocation;
110   /// Location of the current instruction.
111   SourceInfo CurrentSource;
112 
113   /// Next label ID to generate - first label is 1.
114   LabelTy NextLabel = 1;
115   /// Label being executed - 0 is the entry label.
116   LabelTy CurrentLabel = 0;
117   /// Active block which should be executed.
118   LabelTy ActiveLabel = 0;
119 
120   /// Since expressions can only jump forward, predicated execution is
121   /// used to deal with if-else statements.
122   bool isActive() const { return CurrentLabel == ActiveLabel; }
123 
124 protected:
125 #define GET_EVAL_PROTO
126 #include "Opcodes.inc"
127 #undef GET_EVAL_PROTO
128 };
129 
130 } // namespace interp
131 } // namespace clang
132 
133 #endif
134