xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/InterpState.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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