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