Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/InterpState.h
213799 views
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
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, 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
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
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:
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
}
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
225