1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
//===--- InterpState.h - Interpreter state for the constexpr VM -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Definition of the interpreter state and entry point.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_INTERP_INTERPSTATE_H
#define LLVM_CLANG_AST_INTERP_INTERPSTATE_H
#include "Context.h"
#include "DynamicAllocator.h"
#include "Floating.h"
#include "Function.h"
#include "InterpFrame.h"
#include "InterpStack.h"
#include "State.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/OptionalDiagnostic.h"
namespace clang {
namespace interp {
class Context;
class Function;
class InterpStack;
class InterpFrame;
class SourceMapper;
struct StdAllocatorCaller {
const Expr *Call = nullptr;
QualType AllocType;
explicit operator bool() { return Call; }
};
/// Interpreter context.
class InterpState final : public State, public SourceMapper {
public:
InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
SourceMapper *M = nullptr);
InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
const Function *Func);
~InterpState();
void cleanup();
InterpState(const InterpState &) = delete;
InterpState &operator=(const InterpState &) = delete;
bool diagnosing() const { return getEvalStatus().Diag != nullptr; }
// Stack frame accessors.
Frame *getSplitFrame() { return Parent.getCurrentFrame(); }
Frame *getCurrentFrame() override;
unsigned getCallStackDepth() override {
return Current ? (Current->getDepth() + 1) : 1;
}
const Frame *getBottomFrame() const override {
return Parent.getBottomFrame();
}
// Access objects from the walker context.
Expr::EvalStatus &getEvalStatus() const override {
return Parent.getEvalStatus();
}
ASTContext &getASTContext() const override { return Parent.getASTContext(); }
// Forward status checks and updates to the walker.
bool checkingForUndefinedBehavior() const override {
return Parent.checkingForUndefinedBehavior();
}
bool keepEvaluatingAfterFailure() const override {
return Parent.keepEvaluatingAfterFailure();
}
bool keepEvaluatingAfterSideEffect() const override {
return Parent.keepEvaluatingAfterSideEffect();
}
bool checkingPotentialConstantExpression() const override {
return Parent.checkingPotentialConstantExpression();
}
bool noteUndefinedBehavior() override {
return Parent.noteUndefinedBehavior();
}
bool inConstantContext() const;
bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
void setActiveDiagnostic(bool Flag) override {
Parent.setActiveDiagnostic(Flag);
}
void setFoldFailureDiagnostic(bool Flag) override {
Parent.setFoldFailureDiagnostic(Flag);
}
bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
bool noteSideEffect() override { return Parent.noteSideEffect(); }
/// Reports overflow and return true if evaluation should continue.
bool reportOverflow(const Expr *E, const llvm::APSInt &Value);
/// Deallocates a pointer.
void deallocate(Block *B);
/// Delegates source mapping to the mapper.
SourceInfo getSource(const Function *F, CodePtr PC) const override {
if (M)
return M->getSource(F, PC);
assert(F && "Function cannot be null");
return F->getSource(PC);
}
Context &getContext() const { return Ctx; }
void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }
DynamicAllocator &getAllocator() { return Alloc; }
/// Diagnose any dynamic allocations that haven't been freed yet.
/// Will return \c false if there were any allocations to diagnose,
/// \c true otherwise.
bool maybeDiagnoseDanglingAllocations();
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const;
void *allocate(size_t Size, unsigned Align = 8) const {
return Allocator.Allocate(Size, Align);
}
template <typename T> T *allocate(size_t Num = 1) const {
return static_cast<T *>(allocate(Num * sizeof(T), alignof(T)));
}
template <typename T> T allocAP(unsigned BitWidth) {
unsigned NumWords = APInt::getNumWords(BitWidth);
if (NumWords == 1)
return T(BitWidth);
uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));
// std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
return T(Mem, BitWidth);
}
Floating allocFloat(const llvm::fltSemantics &Sem) {
if (Floating::singleWord(Sem))
return Floating(llvm::APFloatBase::SemanticsToEnum(Sem));
unsigned NumWords =
APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem));
uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));
// std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug
return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem));
}
private:
friend class EvaluationResult;
friend class InterpStateCCOverride;
/// AST Walker state.
State &Parent;
/// Dead block chain.
DeadBlock *DeadBlocks = nullptr;
/// Reference to the offset-source mapping.
SourceMapper *M;
/// Allocator used for dynamic allocations performed via the program.
DynamicAllocator Alloc;
public:
/// Reference to the module containing all bytecode.
Program &P;
/// Temporary stack.
InterpStack &Stk;
/// Interpreter Context.
Context &Ctx;
/// Bottom function frame.
InterpFrame BottomFrame;
/// The current frame.
InterpFrame *Current = nullptr;
/// Source location of the evaluating expression
SourceLocation EvalLocation;
/// Declaration we're initializing/evaluting, if any.
const VarDecl *EvaluatingDecl = nullptr;
/// Things needed to do speculative execution.
SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr;
unsigned SpeculationDepth = 0;
std::optional<bool> ConstantContextOverride;
llvm::SmallVector<
std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
SeenGlobalTemporaries;
/// List of blocks we're currently running either constructors or destructors
/// for.
llvm::SmallVector<const Block *> InitializingBlocks;
mutable llvm::BumpPtrAllocator Allocator;
};
class InterpStateCCOverride final {
public:
InterpStateCCOverride(InterpState &Ctx, bool Value)
: Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) {
// We only override this if the new value is true.
Enabled = Value;
if (Enabled)
Ctx.ConstantContextOverride = Value;
}
~InterpStateCCOverride() {
if (Enabled)
Ctx.ConstantContextOverride = OldCC;
}
private:
bool Enabled;
InterpState &Ctx;
std::optional<bool> OldCC;
};
} // namespace interp
} // namespace clang
#endif
|