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