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