clang 24.0.0git
InterpState.h
Go to the documentation of this file.
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
24namespace clang {
25namespace interp {
26class Context;
27class SourceMapper;
28
30 const Expr *Call = nullptr;
32 explicit operator bool() { return Call; }
33};
34
35// FIXME: Create one for the "checking potential constant expression"
36// evaluation.
37enum class EvaluationKind : uint8_t {
39 Dtor, /// We're checking for constant destruction of a global variable.
40};
41
42/// Interpreter context.
43class InterpState final : public State {
44public:
45 InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
46 SourceMapper *M = nullptr);
47 InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
48 const Function *Func);
49
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 const Frame *getCurrentFrame() override;
61 unsigned getCallStackDepth() override {
62 return Current ? (Current->getDepth() + 1) : 1;
63 }
64 bool stepsLeft() const override { return true; }
65 bool inConstantContext() const;
66
67 /// Deallocates a pointer.
68 void deallocate(Block *B);
69
70 /// Delegates source mapping to the mapper.
71 SourceInfo getSource(CodePtr PC) const { return M->getSource(PC); }
72 const Expr *getExpr(CodePtr PC) const { return getSource(PC).asExpr(); }
74 return getSource(PC).getLoc();
75 }
77
78 Context &getContext() const { return Ctx; }
79
81
83 if (!Alloc) {
84 Alloc = std::make_unique<DynamicAllocator>();
85 }
86
87 return *Alloc;
88 }
89
90 /// Diagnose any dynamic allocations that haven't been freed yet.
91 /// Will return \c false if there were any allocations to diagnose,
92 /// \c true otherwise.
94
95 StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const;
96
97 void *allocate(size_t Size, unsigned Align = 8) const {
98 if (!Allocator)
99 Allocator.emplace();
100 return Allocator->Allocate(Size, Align);
101 }
102 template <typename T> T *allocate(size_t Num = 1) const {
103 return static_cast<T *>(allocate(Num * sizeof(T), alignof(T)));
104 }
105
106 template <typename T> T allocAP(unsigned BitWidth) {
107 unsigned NumWords = APInt::getNumWords(BitWidth);
108 if (NumWords == 1)
109 return T(BitWidth);
110 uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));
111 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
112 return T(Mem, BitWidth);
113 }
114
115 Floating allocFloat(const llvm::fltSemantics &Sem) {
116 if (Floating::singleWord(Sem))
117 return Floating(llvm::APFloatBase::SemanticsToEnum(Sem));
118
119 unsigned NumWords =
120 APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem));
121 uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));
122 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
123 return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem));
124 }
125 const CXXRecordDecl **allocMemberPointerPath(unsigned Length) {
126 return reinterpret_cast<const CXXRecordDecl **>(
127 this->allocate(Length * sizeof(CXXRecordDecl *)));
128 }
129
130 /// Note that a step has been executed. If there are no more steps remaining,
131 /// diagnoses and returns \c false.
132 bool noteStep(CodePtr OpPC);
133
134 bool initializingBlock(const Block *B) const {
136 if (V.block() == B)
137 return true;
138 return false;
139 }
140
141 bool lifetimeStartedInEvaluation(const Block *B) const {
143 return B->getEvalID() == EvalID;
144
146 assert(EvaluatingDecl);
148 return EvaluatingDecl->getType().isConstQualified();
149 }
150 return false;
151 }
152
153 /// Return if we're checking if a global variable has a constant destructor.
156 }
157 /// Return if we're checking if a global variable has a constant destructor
158 /// and the given pointer is pointing to the variable we're checking that for.
159 bool checkingConstantDestruction(const Pointer &Ptr) const {
161 }
162 bool checkingConstantDestruction(const VarDecl *VD) const {
164 }
165
166private:
167 friend class EvaluationResult;
169 /// Dead block chain.
170 DeadBlock *DeadBlocks = nullptr;
171 /// Reference to the offset-source mapping.
172 SourceMapper *M;
173 /// Allocator used for dynamic allocations performed via the program.
174 std::unique_ptr<DynamicAllocator> Alloc;
175 /// Allocator for everything else, e.g. floating-point values.
176 mutable std::optional<llvm::BumpPtrAllocator> Allocator;
177
178public:
180 /// Reference to the module containing all bytecode.
182 /// Temporary stack.
184 /// Interpreter Context.
186 /// Bottom function frame.
188 /// The current frame.
190 /// Source location of the evaluating expression
192 /// Declaration we're initializing/evaluting, if any.
193 const VarDecl *EvaluatingDecl = nullptr;
194 /// Steps left during evaluation.
195 unsigned StepsLeft = 1;
196 /// Whether infinite evaluation steps have been requested. If this is false,
197 /// we use the StepsLeft value above.
198 const bool InfiniteSteps = false;
199 /// ID identifying this evaluation.
200 const unsigned EvalID;
201
203
204 /// Things needed to do speculative execution.
206 bool PrevDiagsEmitted = false;
207#ifndef NDEBUG
208 unsigned SpeculationDepth = 0;
209#endif
210 unsigned DiagIgnoreDepth = 0;
211 std::optional<bool> ConstantContextOverride;
212
214 std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
216
217 /// List of blocks we're currently running either constructors or destructors
218 /// for.
220};
221
223public:
225 : Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) {
226 // We only override this if the new value is true.
227 Enabled = Value;
228 if (Enabled)
229 Ctx.ConstantContextOverride = Value;
230 }
232 if (Enabled)
233 Ctx.ConstantContextOverride = OldCC;
234 }
235
236private:
237 bool Enabled;
238 InterpState &Ctx;
239 std::optional<bool> OldCC;
240};
241
242} // namespace interp
243} // namespace clang
244
245#endif
#define V(N, I)
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
This represents one expression.
Definition Expr.h:112
A (possibly-)qualified type.
Definition TypeBase.h:938
Encodes a location in the source.
A trivial tuple used to represent a source range.
Represents a variable declaration or definition.
Definition Decl.h:932
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:44
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition InterpBlock.h:73
unsigned getEvalID() const
The Evaluation ID this block was created in.
Definition InterpBlock.h:94
Pointer into the code segment.
Definition Source.h:31
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:47
Descriptor for a dead block.
Manages dynamic memory allocations done during bytecode interpretation.
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition Floating.h:35
bool singleWord() const
Definition Floating.h:107
Base class for stack frames, shared between VM and walker.
Definition Frame.h:25
Bytecode function.
Definition Function.h:99
Frame storing local variables.
Definition InterpFrame.h:27
Stack frame storing temporaries and parameters.
Definition InterpStack.h:25
InterpStateCCOverride(InterpState &Ctx, bool Value)
Interpreter context.
Definition InterpState.h:43
SmallVectorImpl< PartialDiagnosticAt > * PrevDiags
Things needed to do speculative execution.
const Expr * getExpr(CodePtr PC) const
Definition InterpState.h:72
bool lifetimeStartedInEvaluation(const Block *B) const
unsigned getCallStackDepth() override
Definition InterpState.h:61
InterpFrame BottomFrame
Bottom function frame.
Context & getContext() const
Definition InterpState.h:78
bool initializingBlock(const Block *B) const
DynamicAllocator & getAllocator()
Definition InterpState.h:82
SourceLocation getLocation(CodePtr PC) const
Definition InterpState.h:73
Context & Ctx
Interpreter Context.
void * allocate(size_t Size, unsigned Align=8) const
Definition InterpState.h:97
bool noteStep(CodePtr OpPC)
Note that a step has been executed.
Floating allocFloat(const llvm::fltSemantics &Sem)
const unsigned EvalID
ID identifying this evaluation.
SourceInfo getSource(CodePtr PC) const
Delegates source mapping to the mapper.
Definition InterpState.h:71
InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx, SourceMapper *M=nullptr)
InterpState(const InterpState &)=delete
bool stepsLeft() const override
Definition InterpState.h:64
llvm::SmallVector< std::pair< const Expr *, const LifetimeExtendedTemporaryDecl * > > SeenGlobalTemporaries
InterpStack & Stk
Temporary stack.
bool maybeDiagnoseDanglingAllocations()
Diagnose any dynamic allocations that haven't been freed yet.
SourceRange getRange(CodePtr PC) const
Definition InterpState.h:76
SourceLocation EvalLocation
Source location of the evaluating expression.
bool checkingConstantDestruction() const
Return if we're checking if a global variable has a constant destructor.
unsigned StepsLeft
Steps left during evaluation.
const VarDecl * EvaluatingDecl
Declaration we're initializing/evaluting, if any.
bool checkingConstantDestruction(const Pointer &Ptr) const
Return if we're checking if a global variable has a constant destructor and the given pointer is poin...
InterpFrame * Current
The current frame.
const CXXRecordDecl ** allocMemberPointerPath(unsigned Length)
const Frame * getCurrentFrame() override
std::optional< bool > ConstantContextOverride
const bool InfiniteSteps
Whether infinite evaluation steps have been requested.
InterpState & operator=(const InterpState &)=delete
friend class InterpStateCCOverride
T * allocate(size_t Num=1) const
void deallocate(Block *B)
Deallocates a pointer.
llvm::SmallVector< PtrView > InitializingPtrs
List of blocks we're currently running either constructors or destructors for.
T allocAP(unsigned BitWidth)
void setEvalLocation(SourceLocation SL)
Definition InterpState.h:80
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const
bool checkingConstantDestruction(const VarDecl *VD) const
Program & P
Reference to the module containing all bytecode.
A pointer to a memory block, live or dead.
Definition Pointer.h:405
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:536
The program contains and links the bytecode for all functions.
Definition Program.h:37
Describes the statement/declaration an opcode was generated from.
Definition Source.h:77
const Expr * asExpr() const
Definition Source.h:92
SourceLocation getLoc() const
Definition Source.cpp:15
SourceRange getRange() const
Definition Source.cpp:25
Interface for classes which map locations to sources.
Definition Source.h:127
Expr::EvalStatus & getEvalStatus() const
Definition State.h:91
State(ASTContext &ASTCtx, Expr::EvalStatus &EvalStatus)
Definition State.h:83
Top level wrappers for InstallAPI frontend operations.
const FunctionProtoType * T
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 uint8_t
SmallVectorImpl< PartialDiagnosticAt > * Diag
Diag - If this is non-null, it will be filled in with a stack of notes indicating why evaluation fail...
Definition Expr.h:641
const VarDecl * asVarDecl() const
Definition Descriptor.h:218