xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/EvalEmitter.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===--- EvalEmitter.h - Instruction emitter for the VM ---------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // Defines the instruction emitters.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_EVALEMITTER_H
14*700637cbSDimitry Andric #define LLVM_CLANG_AST_INTERP_EVALEMITTER_H
15*700637cbSDimitry Andric 
16*700637cbSDimitry Andric #include "EvaluationResult.h"
17*700637cbSDimitry Andric #include "InterpState.h"
18*700637cbSDimitry Andric #include "PrimType.h"
19*700637cbSDimitry Andric #include "Source.h"
20*700637cbSDimitry Andric 
21*700637cbSDimitry Andric namespace clang {
22*700637cbSDimitry Andric namespace interp {
23*700637cbSDimitry Andric class Context;
24*700637cbSDimitry Andric class Function;
25*700637cbSDimitry Andric class InterpStack;
26*700637cbSDimitry Andric class Program;
27*700637cbSDimitry Andric enum Opcode : uint32_t;
28*700637cbSDimitry Andric 
29*700637cbSDimitry Andric /// An emitter which evaluates opcodes as they are emitted.
30*700637cbSDimitry Andric class EvalEmitter : public SourceMapper {
31*700637cbSDimitry Andric public:
32*700637cbSDimitry Andric   using LabelTy = uint32_t;
33*700637cbSDimitry Andric   using AddrTy = uintptr_t;
34*700637cbSDimitry Andric   using Local = Scope::Local;
35*700637cbSDimitry Andric   using PtrCallback = llvm::function_ref<bool(const Pointer &)>;
36*700637cbSDimitry Andric 
37*700637cbSDimitry Andric   EvaluationResult interpretExpr(const Expr *E,
38*700637cbSDimitry Andric                                  bool ConvertResultToRValue = false,
39*700637cbSDimitry Andric                                  bool DestroyToplevelScope = false);
40*700637cbSDimitry Andric   EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized);
41*700637cbSDimitry Andric   /// Interpret the given Expr to a Pointer.
42*700637cbSDimitry Andric   EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB);
43*700637cbSDimitry Andric 
44*700637cbSDimitry Andric   /// Clean up all resources.
45*700637cbSDimitry Andric   void cleanup();
46*700637cbSDimitry Andric 
47*700637cbSDimitry Andric protected:
48*700637cbSDimitry Andric   EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk);
49*700637cbSDimitry Andric 
50*700637cbSDimitry Andric   virtual ~EvalEmitter();
51*700637cbSDimitry Andric 
52*700637cbSDimitry Andric   /// Define a label.
53*700637cbSDimitry Andric   void emitLabel(LabelTy Label);
54*700637cbSDimitry Andric   /// Create a label.
55*700637cbSDimitry Andric   LabelTy getLabel();
56*700637cbSDimitry Andric 
57*700637cbSDimitry Andric   /// Methods implemented by the compiler.
58*700637cbSDimitry Andric   virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0;
59*700637cbSDimitry Andric   virtual bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) = 0;
60*700637cbSDimitry Andric   virtual bool visitFunc(const FunctionDecl *F) = 0;
61*700637cbSDimitry Andric   virtual bool visit(const Expr *E) = 0;
62*700637cbSDimitry Andric   virtual bool emitBool(bool V, const Expr *E) = 0;
63*700637cbSDimitry Andric 
64*700637cbSDimitry Andric   /// Emits jumps.
65*700637cbSDimitry Andric   bool jumpTrue(const LabelTy &Label);
66*700637cbSDimitry Andric   bool jumpFalse(const LabelTy &Label);
67*700637cbSDimitry Andric   bool jump(const LabelTy &Label);
68*700637cbSDimitry Andric   bool fallthrough(const LabelTy &Label);
69*700637cbSDimitry Andric   /// Speculative execution.
70*700637cbSDimitry Andric   bool speculate(const CallExpr *E, const LabelTy &EndLabel);
71*700637cbSDimitry Andric 
72*700637cbSDimitry Andric   /// Since expressions can only jump forward, predicated execution is
73*700637cbSDimitry Andric   /// used to deal with if-else statements.
isActive()74*700637cbSDimitry Andric   bool isActive() const { return CurrentLabel == ActiveLabel; }
checkingForUndefinedBehavior()75*700637cbSDimitry Andric   bool checkingForUndefinedBehavior() const {
76*700637cbSDimitry Andric     return S.checkingForUndefinedBehavior();
77*700637cbSDimitry Andric   }
78*700637cbSDimitry Andric 
79*700637cbSDimitry Andric   /// Callback for registering a local.
80*700637cbSDimitry Andric   Local createLocal(Descriptor *D);
81*700637cbSDimitry Andric 
82*700637cbSDimitry Andric   /// Returns the source location of the current opcode.
getSource(const Function * F,CodePtr PC)83*700637cbSDimitry Andric   SourceInfo getSource(const Function *F, CodePtr PC) const override {
84*700637cbSDimitry Andric     return (F && F->hasBody()) ? F->getSource(PC) : CurrentSource;
85*700637cbSDimitry Andric   }
86*700637cbSDimitry Andric 
87*700637cbSDimitry Andric   /// Parameter indices.
88*700637cbSDimitry Andric   llvm::DenseMap<const ParmVarDecl *, ParamOffset> Params;
89*700637cbSDimitry Andric   /// Lambda captures.
90*700637cbSDimitry Andric   llvm::DenseMap<const ValueDecl *, ParamOffset> LambdaCaptures;
91*700637cbSDimitry Andric   /// Offset of the This parameter in a lambda record.
92*700637cbSDimitry Andric   ParamOffset LambdaThisCapture{0, false};
93*700637cbSDimitry Andric   /// Local descriptors.
94*700637cbSDimitry Andric   llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
95*700637cbSDimitry Andric 
96*700637cbSDimitry Andric private:
97*700637cbSDimitry Andric   /// Current compilation context.
98*700637cbSDimitry Andric   Context &Ctx;
99*700637cbSDimitry Andric   /// Current program.
100*700637cbSDimitry Andric   Program &P;
101*700637cbSDimitry Andric   /// Callee evaluation state.
102*700637cbSDimitry Andric   InterpState S;
103*700637cbSDimitry Andric   /// Location to write the result to.
104*700637cbSDimitry Andric   EvaluationResult EvalResult;
105*700637cbSDimitry Andric   /// Whether the result should be converted to an RValue.
106*700637cbSDimitry Andric   bool ConvertResultToRValue = false;
107*700637cbSDimitry Andric   /// Whether we should check if the result has been fully
108*700637cbSDimitry Andric   /// initialized.
109*700637cbSDimitry Andric   bool CheckFullyInitialized = false;
110*700637cbSDimitry Andric   /// Callback to call when using interpretAsPointer.
111*700637cbSDimitry Andric   std::optional<PtrCallback> PtrCB;
112*700637cbSDimitry Andric 
113*700637cbSDimitry Andric   /// Temporaries which require storage.
114*700637cbSDimitry Andric   llvm::SmallVector<std::unique_ptr<char[]>> Locals;
115*700637cbSDimitry Andric 
getLocal(unsigned Index)116*700637cbSDimitry Andric   Block *getLocal(unsigned Index) const {
117*700637cbSDimitry Andric     assert(Index < Locals.size());
118*700637cbSDimitry Andric     return reinterpret_cast<Block *>(Locals[Index].get());
119*700637cbSDimitry Andric   }
120*700637cbSDimitry Andric 
121*700637cbSDimitry Andric   void updateGlobalTemporaries();
122*700637cbSDimitry Andric 
123*700637cbSDimitry Andric   // The emitter always tracks the current instruction and sets OpPC to a token
124*700637cbSDimitry Andric   // value which is mapped to the location of the opcode being evaluated.
125*700637cbSDimitry Andric   CodePtr OpPC;
126*700637cbSDimitry Andric   /// Location of the current instruction.
127*700637cbSDimitry Andric   SourceInfo CurrentSource;
128*700637cbSDimitry Andric 
129*700637cbSDimitry Andric   /// Next label ID to generate - first label is 1.
130*700637cbSDimitry Andric   LabelTy NextLabel = 1;
131*700637cbSDimitry Andric   /// Label being executed - 0 is the entry label.
132*700637cbSDimitry Andric   LabelTy CurrentLabel = 0;
133*700637cbSDimitry Andric   /// Active block which should be executed.
134*700637cbSDimitry Andric   LabelTy ActiveLabel = 0;
135*700637cbSDimitry Andric 
136*700637cbSDimitry Andric protected:
137*700637cbSDimitry Andric #define GET_EVAL_PROTO
138*700637cbSDimitry Andric #include "Opcodes.inc"
139*700637cbSDimitry Andric #undef GET_EVAL_PROTO
140*700637cbSDimitry Andric };
141*700637cbSDimitry Andric 
142*700637cbSDimitry Andric } // namespace interp
143*700637cbSDimitry Andric } // namespace clang
144*700637cbSDimitry Andric 
145*700637cbSDimitry Andric #endif
146