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
28namespace clang {
29namespace interp {
30class Context;
31class Function;
32class InterpStack;
33class InterpFrame;
34class SourceMapper;
35
36struct StdAllocatorCaller {
37 const Expr *Call = nullptr;
38 QualType AllocType;
39 explicit operator bool() { return Call; }
40};
41
42/// Interpreter context.
43class InterpState final : public State, public SourceMapper {
44public:
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
57 bool diagnosing() const { return getEvalStatus().Diag != nullptr; }
58
59 // Stack frame accessors.
60 Frame *getSplitFrame() { return Parent.getCurrentFrame(); }
61 Frame *getCurrentFrame() override;
62 unsigned getCallStackDepth() override {
63 return Current ? (Current->getDepth() + 1) : 1;
64 }
65 const Frame *getBottomFrame() const override {
66 return Parent.getBottomFrame();
67 }
68
69 // Access objects from the walker context.
70 Expr::EvalStatus &getEvalStatus() const override {
71 return Parent.getEvalStatus();
72 }
73 ASTContext &getASTContext() const override { return Parent.getASTContext(); }
74
75 // Forward status checks and updates to the walker.
76 bool checkingForUndefinedBehavior() const override {
77 return Parent.checkingForUndefinedBehavior();
78 }
79 bool keepEvaluatingAfterFailure() const override {
80 return Parent.keepEvaluatingAfterFailure();
81 }
82 bool keepEvaluatingAfterSideEffect() const override {
83 return Parent.keepEvaluatingAfterSideEffect();
84 }
85 bool checkingPotentialConstantExpression() const override {
86 return Parent.checkingPotentialConstantExpression();
87 }
88 bool noteUndefinedBehavior() override {
89 return Parent.noteUndefinedBehavior();
90 }
91 bool inConstantContext() const;
92 bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
93 void setActiveDiagnostic(bool Flag) override {
94 Parent.setActiveDiagnostic(Flag);
95 }
96 void setFoldFailureDiagnostic(bool Flag) override {
97 Parent.setFoldFailureDiagnostic(Flag);
98 }
99 bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
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.
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
117 Context &getContext() const { return Ctx; }
118
119 void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }
120
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, Alignment: Align);
132 }
133 template <typename T> T *allocate(size_t Num = 1) const {
134 return static_cast<T *>(allocate(Size: Num * sizeof(T), Align: alignof(T)));
135 }
136
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(Size: NumWords * sizeof(uint64_t));
142 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
143 return T(Mem, BitWidth);
144 }
145
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(BitWidth: llvm::APFloatBase::getSizeInBits(Sem));
152 uint64_t *Mem = (uint64_t *)this->allocate(Size: NumWords * sizeof(uint64_t));
153 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
154 return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem));
155 }
156
157private:
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
169public:
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 mutable llvm::BumpPtrAllocator Allocator;
194};
195
196class InterpStateCCOverride final {
197public:
198 InterpStateCCOverride(InterpState &Ctx, bool Value)
199 : Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) {
200 // We only override this if the new value is true.
201 Enabled = Value;
202 if (Enabled)
203 Ctx.ConstantContextOverride = Value;
204 }
205 ~InterpStateCCOverride() {
206 if (Enabled)
207 Ctx.ConstantContextOverride = OldCC;
208 }
209
210private:
211 bool Enabled;
212 InterpState &Ctx;
213 std::optional<bool> OldCC;
214};
215
216} // namespace interp
217} // namespace clang
218
219#endif
220