1*700637cbSDimitry Andric //===--- InterpState.h - Interpreter state for the constexpr 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 // Definition of the interpreter state and entry point. 10*700637cbSDimitry Andric // 11*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 12*700637cbSDimitry Andric 13*700637cbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTERPSTATE_H 14*700637cbSDimitry Andric #define LLVM_CLANG_AST_INTERP_INTERPSTATE_H 15*700637cbSDimitry Andric 16*700637cbSDimitry Andric #include "Context.h" 17*700637cbSDimitry Andric #include "DynamicAllocator.h" 18*700637cbSDimitry Andric #include "Floating.h" 19*700637cbSDimitry Andric #include "Function.h" 20*700637cbSDimitry Andric #include "InterpFrame.h" 21*700637cbSDimitry Andric #include "InterpStack.h" 22*700637cbSDimitry Andric #include "State.h" 23*700637cbSDimitry Andric #include "clang/AST/APValue.h" 24*700637cbSDimitry Andric #include "clang/AST/ASTDiagnostic.h" 25*700637cbSDimitry Andric #include "clang/AST/Expr.h" 26*700637cbSDimitry Andric #include "clang/AST/OptionalDiagnostic.h" 27*700637cbSDimitry Andric 28*700637cbSDimitry Andric namespace clang { 29*700637cbSDimitry Andric namespace interp { 30*700637cbSDimitry Andric class Context; 31*700637cbSDimitry Andric class Function; 32*700637cbSDimitry Andric class InterpStack; 33*700637cbSDimitry Andric class InterpFrame; 34*700637cbSDimitry Andric class SourceMapper; 35*700637cbSDimitry Andric 36*700637cbSDimitry Andric struct StdAllocatorCaller { 37*700637cbSDimitry Andric const Expr *Call = nullptr; 38*700637cbSDimitry Andric QualType AllocType; 39*700637cbSDimitry Andric explicit operator bool() { return Call; } 40*700637cbSDimitry Andric }; 41*700637cbSDimitry Andric 42*700637cbSDimitry Andric /// Interpreter context. 43*700637cbSDimitry Andric class InterpState final : public State, public SourceMapper { 44*700637cbSDimitry Andric public: 45*700637cbSDimitry Andric InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx, 46*700637cbSDimitry Andric SourceMapper *M = nullptr); 47*700637cbSDimitry Andric InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx, 48*700637cbSDimitry Andric const Function *Func); 49*700637cbSDimitry Andric 50*700637cbSDimitry Andric ~InterpState(); 51*700637cbSDimitry Andric 52*700637cbSDimitry Andric void cleanup(); 53*700637cbSDimitry Andric 54*700637cbSDimitry Andric InterpState(const InterpState &) = delete; 55*700637cbSDimitry Andric InterpState &operator=(const InterpState &) = delete; 56*700637cbSDimitry Andric diagnosing()57*700637cbSDimitry Andric bool diagnosing() const { return getEvalStatus().Diag != nullptr; } 58*700637cbSDimitry Andric 59*700637cbSDimitry Andric // Stack frame accessors. getSplitFrame()60*700637cbSDimitry Andric Frame *getSplitFrame() { return Parent.getCurrentFrame(); } 61*700637cbSDimitry Andric Frame *getCurrentFrame() override; getCallStackDepth()62*700637cbSDimitry Andric unsigned getCallStackDepth() override { 63*700637cbSDimitry Andric return Current ? (Current->getDepth() + 1) : 1; 64*700637cbSDimitry Andric } getBottomFrame()65*700637cbSDimitry Andric const Frame *getBottomFrame() const override { 66*700637cbSDimitry Andric return Parent.getBottomFrame(); 67*700637cbSDimitry Andric } 68*700637cbSDimitry Andric 69*700637cbSDimitry Andric // Access objects from the walker context. getEvalStatus()70*700637cbSDimitry Andric Expr::EvalStatus &getEvalStatus() const override { 71*700637cbSDimitry Andric return Parent.getEvalStatus(); 72*700637cbSDimitry Andric } getASTContext()73*700637cbSDimitry Andric ASTContext &getASTContext() const override { return Parent.getASTContext(); } 74*700637cbSDimitry Andric 75*700637cbSDimitry Andric // Forward status checks and updates to the walker. checkingForUndefinedBehavior()76*700637cbSDimitry Andric bool checkingForUndefinedBehavior() const override { 77*700637cbSDimitry Andric return Parent.checkingForUndefinedBehavior(); 78*700637cbSDimitry Andric } keepEvaluatingAfterFailure()79*700637cbSDimitry Andric bool keepEvaluatingAfterFailure() const override { 80*700637cbSDimitry Andric return Parent.keepEvaluatingAfterFailure(); 81*700637cbSDimitry Andric } keepEvaluatingAfterSideEffect()82*700637cbSDimitry Andric bool keepEvaluatingAfterSideEffect() const override { 83*700637cbSDimitry Andric return Parent.keepEvaluatingAfterSideEffect(); 84*700637cbSDimitry Andric } checkingPotentialConstantExpression()85*700637cbSDimitry Andric bool checkingPotentialConstantExpression() const override { 86*700637cbSDimitry Andric return Parent.checkingPotentialConstantExpression(); 87*700637cbSDimitry Andric } noteUndefinedBehavior()88*700637cbSDimitry Andric bool noteUndefinedBehavior() override { 89*700637cbSDimitry Andric return Parent.noteUndefinedBehavior(); 90*700637cbSDimitry Andric } 91*700637cbSDimitry Andric bool inConstantContext() const; hasActiveDiagnostic()92*700637cbSDimitry Andric bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); } setActiveDiagnostic(bool Flag)93*700637cbSDimitry Andric void setActiveDiagnostic(bool Flag) override { 94*700637cbSDimitry Andric Parent.setActiveDiagnostic(Flag); 95*700637cbSDimitry Andric } setFoldFailureDiagnostic(bool Flag)96*700637cbSDimitry Andric void setFoldFailureDiagnostic(bool Flag) override { 97*700637cbSDimitry Andric Parent.setFoldFailureDiagnostic(Flag); 98*700637cbSDimitry Andric } hasPriorDiagnostic()99*700637cbSDimitry Andric bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); } noteSideEffect()100*700637cbSDimitry Andric bool noteSideEffect() override { return Parent.noteSideEffect(); } 101*700637cbSDimitry Andric 102*700637cbSDimitry Andric /// Reports overflow and return true if evaluation should continue. 103*700637cbSDimitry Andric bool reportOverflow(const Expr *E, const llvm::APSInt &Value); 104*700637cbSDimitry Andric 105*700637cbSDimitry Andric /// Deallocates a pointer. 106*700637cbSDimitry Andric void deallocate(Block *B); 107*700637cbSDimitry Andric 108*700637cbSDimitry Andric /// Delegates source mapping to the mapper. getSource(const Function * F,CodePtr PC)109*700637cbSDimitry Andric SourceInfo getSource(const Function *F, CodePtr PC) const override { 110*700637cbSDimitry Andric if (M) 111*700637cbSDimitry Andric return M->getSource(F, PC); 112*700637cbSDimitry Andric 113*700637cbSDimitry Andric assert(F && "Function cannot be null"); 114*700637cbSDimitry Andric return F->getSource(PC); 115*700637cbSDimitry Andric } 116*700637cbSDimitry Andric getContext()117*700637cbSDimitry Andric Context &getContext() const { return Ctx; } 118*700637cbSDimitry Andric setEvalLocation(SourceLocation SL)119*700637cbSDimitry Andric void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; } 120*700637cbSDimitry Andric getAllocator()121*700637cbSDimitry Andric DynamicAllocator &getAllocator() { return Alloc; } 122*700637cbSDimitry Andric 123*700637cbSDimitry Andric /// Diagnose any dynamic allocations that haven't been freed yet. 124*700637cbSDimitry Andric /// Will return \c false if there were any allocations to diagnose, 125*700637cbSDimitry Andric /// \c true otherwise. 126*700637cbSDimitry Andric bool maybeDiagnoseDanglingAllocations(); 127*700637cbSDimitry Andric 128*700637cbSDimitry Andric StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const; 129*700637cbSDimitry Andric 130*700637cbSDimitry Andric void *allocate(size_t Size, unsigned Align = 8) const { 131*700637cbSDimitry Andric return Allocator.Allocate(Size, Align); 132*700637cbSDimitry Andric } 133*700637cbSDimitry Andric template <typename T> T *allocate(size_t Num = 1) const { 134*700637cbSDimitry Andric return static_cast<T *>(allocate(Num * sizeof(T), alignof(T))); 135*700637cbSDimitry Andric } 136*700637cbSDimitry Andric allocAP(unsigned BitWidth)137*700637cbSDimitry Andric template <typename T> T allocAP(unsigned BitWidth) { 138*700637cbSDimitry Andric unsigned NumWords = APInt::getNumWords(BitWidth); 139*700637cbSDimitry Andric if (NumWords == 1) 140*700637cbSDimitry Andric return T(BitWidth); 141*700637cbSDimitry Andric uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t)); 142*700637cbSDimitry Andric // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug 143*700637cbSDimitry Andric return T(Mem, BitWidth); 144*700637cbSDimitry Andric } 145*700637cbSDimitry Andric allocFloat(const llvm::fltSemantics & Sem)146*700637cbSDimitry Andric Floating allocFloat(const llvm::fltSemantics &Sem) { 147*700637cbSDimitry Andric if (Floating::singleWord(Sem)) 148*700637cbSDimitry Andric return Floating(llvm::APFloatBase::SemanticsToEnum(Sem)); 149*700637cbSDimitry Andric 150*700637cbSDimitry Andric unsigned NumWords = 151*700637cbSDimitry Andric APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)); 152*700637cbSDimitry Andric uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t)); 153*700637cbSDimitry Andric // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug 154*700637cbSDimitry Andric return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem)); 155*700637cbSDimitry Andric } 156*700637cbSDimitry Andric 157*700637cbSDimitry Andric private: 158*700637cbSDimitry Andric friend class EvaluationResult; 159*700637cbSDimitry Andric friend class InterpStateCCOverride; 160*700637cbSDimitry Andric /// AST Walker state. 161*700637cbSDimitry Andric State &Parent; 162*700637cbSDimitry Andric /// Dead block chain. 163*700637cbSDimitry Andric DeadBlock *DeadBlocks = nullptr; 164*700637cbSDimitry Andric /// Reference to the offset-source mapping. 165*700637cbSDimitry Andric SourceMapper *M; 166*700637cbSDimitry Andric /// Allocator used for dynamic allocations performed via the program. 167*700637cbSDimitry Andric DynamicAllocator Alloc; 168*700637cbSDimitry Andric 169*700637cbSDimitry Andric public: 170*700637cbSDimitry Andric /// Reference to the module containing all bytecode. 171*700637cbSDimitry Andric Program &P; 172*700637cbSDimitry Andric /// Temporary stack. 173*700637cbSDimitry Andric InterpStack &Stk; 174*700637cbSDimitry Andric /// Interpreter Context. 175*700637cbSDimitry Andric Context &Ctx; 176*700637cbSDimitry Andric /// Bottom function frame. 177*700637cbSDimitry Andric InterpFrame BottomFrame; 178*700637cbSDimitry Andric /// The current frame. 179*700637cbSDimitry Andric InterpFrame *Current = nullptr; 180*700637cbSDimitry Andric /// Source location of the evaluating expression 181*700637cbSDimitry Andric SourceLocation EvalLocation; 182*700637cbSDimitry Andric /// Declaration we're initializing/evaluting, if any. 183*700637cbSDimitry Andric const VarDecl *EvaluatingDecl = nullptr; 184*700637cbSDimitry Andric /// Things needed to do speculative execution. 185*700637cbSDimitry Andric SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr; 186*700637cbSDimitry Andric unsigned SpeculationDepth = 0; 187*700637cbSDimitry Andric std::optional<bool> ConstantContextOverride; 188*700637cbSDimitry Andric 189*700637cbSDimitry Andric llvm::SmallVector< 190*700637cbSDimitry Andric std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>> 191*700637cbSDimitry Andric SeenGlobalTemporaries; 192*700637cbSDimitry Andric 193*700637cbSDimitry Andric /// List of blocks we're currently running either constructors or destructors 194*700637cbSDimitry Andric /// for. 195*700637cbSDimitry Andric llvm::SmallVector<const Block *> InitializingBlocks; 196*700637cbSDimitry Andric 197*700637cbSDimitry Andric mutable llvm::BumpPtrAllocator Allocator; 198*700637cbSDimitry Andric }; 199*700637cbSDimitry Andric 200*700637cbSDimitry Andric class InterpStateCCOverride final { 201*700637cbSDimitry Andric public: InterpStateCCOverride(InterpState & Ctx,bool Value)202*700637cbSDimitry Andric InterpStateCCOverride(InterpState &Ctx, bool Value) 203*700637cbSDimitry Andric : Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) { 204*700637cbSDimitry Andric // We only override this if the new value is true. 205*700637cbSDimitry Andric Enabled = Value; 206*700637cbSDimitry Andric if (Enabled) 207*700637cbSDimitry Andric Ctx.ConstantContextOverride = Value; 208*700637cbSDimitry Andric } ~InterpStateCCOverride()209*700637cbSDimitry Andric ~InterpStateCCOverride() { 210*700637cbSDimitry Andric if (Enabled) 211*700637cbSDimitry Andric Ctx.ConstantContextOverride = OldCC; 212*700637cbSDimitry Andric } 213*700637cbSDimitry Andric 214*700637cbSDimitry Andric private: 215*700637cbSDimitry Andric bool Enabled; 216*700637cbSDimitry Andric InterpState &Ctx; 217*700637cbSDimitry Andric std::optional<bool> OldCC; 218*700637cbSDimitry Andric }; 219*700637cbSDimitry Andric 220*700637cbSDimitry Andric } // namespace interp 221*700637cbSDimitry Andric } // namespace clang 222*700637cbSDimitry Andric 223*700637cbSDimitry Andric #endif 224