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