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
29struct StdAllocatorCaller {
30 const Expr *Call = nullptr;
31 QualType AllocType;
32 explicit operator bool() { return Call; }
33};
34
35/// Interpreter context.
36class InterpState final : public State, public SourceMapper {
37public:
38 InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
39 SourceMapper *M = nullptr);
40 InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
41 const Function *Func);
42
43 ~InterpState();
44
45 void cleanup();
46
47 InterpState(const InterpState &) = delete;
48 InterpState &operator=(const InterpState &) = delete;
49
50 bool diagnosing() const { return getEvalStatus().Diag != nullptr; }
51
52 // Stack frame accessors.
53 const Frame *getCurrentFrame() override;
54 unsigned getCallStackDepth() override {
55 return Current ? (Current->getDepth() + 1) : 1;
56 }
57 const Frame *getBottomFrame() const override { return &BottomFrame; }
58
59 bool stepsLeft() const override { return true; }
60 bool inConstantContext() const;
61
62 /// Deallocates a pointer.
63 void deallocate(Block *B);
64
65 /// Delegates source mapping to the mapper.
66 SourceInfo getSource(const Function *F, CodePtr PC) const override {
67 if (M)
68 return M->getSource(F, PC);
69
70 assert(F && "Function cannot be null");
71 return F->getSource(PC);
72 }
73
74 Context &getContext() const { return Ctx; }
75
76 void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }
77
78 DynamicAllocator &getAllocator() {
79 if (!Alloc) {
80 Alloc = std::make_unique<DynamicAllocator>();
81 }
82
83 return *Alloc;
84 }
85
86 /// Diagnose any dynamic allocations that haven't been freed yet.
87 /// Will return \c false if there were any allocations to diagnose,
88 /// \c true otherwise.
89 bool maybeDiagnoseDanglingAllocations();
90
91 StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const;
92
93 void *allocate(size_t Size, unsigned Align = 8) const {
94 if (!Allocator)
95 Allocator.emplace();
96 return Allocator->Allocate(Size, Alignment: Align);
97 }
98 template <typename T> T *allocate(size_t Num = 1) const {
99 return static_cast<T *>(allocate(Size: Num * sizeof(T), Align: alignof(T)));
100 }
101
102 template <typename T> T allocAP(unsigned BitWidth) {
103 unsigned NumWords = APInt::getNumWords(BitWidth);
104 if (NumWords == 1)
105 return T(BitWidth);
106 uint64_t *Mem = (uint64_t *)this->allocate(Size: NumWords * sizeof(uint64_t));
107 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
108 return T(Mem, BitWidth);
109 }
110
111 Floating allocFloat(const llvm::fltSemantics &Sem) {
112 if (Floating::singleWord(Sem))
113 return Floating(llvm::APFloatBase::SemanticsToEnum(Sem));
114
115 unsigned NumWords =
116 APInt::getNumWords(BitWidth: llvm::APFloatBase::getSizeInBits(Sem));
117 uint64_t *Mem = (uint64_t *)this->allocate(Size: NumWords * sizeof(uint64_t));
118 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
119 return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem));
120 }
121 const CXXRecordDecl **allocMemberPointerPath(unsigned Length) {
122 return reinterpret_cast<const CXXRecordDecl **>(
123 this->allocate(Size: Length * sizeof(CXXRecordDecl *)));
124 }
125
126 /// Note that a step has been executed. If there are no more steps remaining,
127 /// diagnoses and returns \c false.
128 bool noteStep(CodePtr OpPC);
129
130private:
131 friend class EvaluationResult;
132 friend class InterpStateCCOverride;
133 /// Dead block chain.
134 DeadBlock *DeadBlocks = nullptr;
135 /// Reference to the offset-source mapping.
136 SourceMapper *M;
137 /// Allocator used for dynamic allocations performed via the program.
138 std::unique_ptr<DynamicAllocator> Alloc;
139 /// Allocator for everything else, e.g. floating-point values.
140 mutable std::optional<llvm::BumpPtrAllocator> Allocator;
141
142public:
143 /// Reference to the module containing all bytecode.
144 Program &P;
145 /// Temporary stack.
146 InterpStack &Stk;
147 /// Interpreter Context.
148 Context &Ctx;
149 /// Bottom function frame.
150 InterpFrame BottomFrame;
151 /// The current frame.
152 InterpFrame *Current = nullptr;
153 /// Source location of the evaluating expression
154 SourceLocation EvalLocation;
155 /// Declaration we're initializing/evaluting, if any.
156 const VarDecl *EvaluatingDecl = nullptr;
157 /// Steps left during evaluation.
158 unsigned StepsLeft = 1;
159 /// Whether infinite evaluation steps have been requested. If this is false,
160 /// we use the StepsLeft value above.
161 const bool InfiniteSteps = false;
162
163 /// Things needed to do speculative execution.
164 SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr;
165 unsigned SpeculationDepth = 0;
166 std::optional<bool> ConstantContextOverride;
167
168 llvm::SmallVector<
169 std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
170 SeenGlobalTemporaries;
171
172 /// List of blocks we're currently running either constructors or destructors
173 /// for.
174 llvm::SmallVector<const Block *> InitializingBlocks;
175};
176
177class InterpStateCCOverride final {
178public:
179 InterpStateCCOverride(InterpState &Ctx, bool Value)
180 : Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) {
181 // We only override this if the new value is true.
182 Enabled = Value;
183 if (Enabled)
184 Ctx.ConstantContextOverride = Value;
185 }
186 ~InterpStateCCOverride() {
187 if (Enabled)
188 Ctx.ConstantContextOverride = OldCC;
189 }
190
191private:
192 bool Enabled;
193 InterpState &Ctx;
194 std::optional<bool> OldCC;
195};
196
197} // namespace interp
198} // namespace clang
199
200#endif
201