223 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// Definition of the interpreter state and entry point.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_AST_INTERP_INTERPSTATE_H14#define LLVM_CLANG_AST_INTERP_INTERPSTATE_H15 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 *getCurrentFrame() override;61 unsigned getCallStackDepth() override {62 return Current ? (Current->getDepth() + 1) : 1;63 }64 const Frame *getBottomFrame() const override { return &BottomFrame; }65 66 // Access objects from the walker context.67 Expr::EvalStatus &getEvalStatus() const override {68 return Parent.getEvalStatus();69 }70 ASTContext &getASTContext() const override { return Ctx.getASTContext(); }71 const LangOptions &getLangOpts() const {72 return Ctx.getASTContext().getLangOpts();73 }74 75 // Forward status checks and updates to the walker.76 bool keepEvaluatingAfterFailure() const override {77 return Parent.keepEvaluatingAfterFailure();78 }79 bool keepEvaluatingAfterSideEffect() const override {80 return Parent.keepEvaluatingAfterSideEffect();81 }82 bool noteUndefinedBehavior() override {83 return Parent.noteUndefinedBehavior();84 }85 bool inConstantContext() const;86 bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }87 void setActiveDiagnostic(bool Flag) override {88 Parent.setActiveDiagnostic(Flag);89 }90 void setFoldFailureDiagnostic(bool Flag) override {91 Parent.setFoldFailureDiagnostic(Flag);92 }93 bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }94 bool noteSideEffect() override { return Parent.noteSideEffect(); }95 96 /// Deallocates a pointer.97 void deallocate(Block *B);98 99 /// Delegates source mapping to the mapper.100 SourceInfo getSource(const Function *F, CodePtr PC) const override {101 if (M)102 return M->getSource(F, PC);103 104 assert(F && "Function cannot be null");105 return F->getSource(PC);106 }107 108 Context &getContext() const { return Ctx; }109 110 void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }111 112 DynamicAllocator &getAllocator() {113 if (!Alloc) {114 Alloc = std::make_unique<DynamicAllocator>();115 }116 117 return *Alloc;118 }119 120 /// Diagnose any dynamic allocations that haven't been freed yet.121 /// Will return \c false if there were any allocations to diagnose,122 /// \c true otherwise.123 bool maybeDiagnoseDanglingAllocations();124 125 StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const;126 127 void *allocate(size_t Size, unsigned Align = 8) const {128 if (!Allocator)129 Allocator.emplace();130 return Allocator->Allocate(Size, Align);131 }132 template <typename T> T *allocate(size_t Num = 1) const {133 return static_cast<T *>(allocate(Num * sizeof(T), alignof(T)));134 }135 136 template <typename T> T allocAP(unsigned BitWidth) {137 unsigned NumWords = APInt::getNumWords(BitWidth);138 if (NumWords == 1)139 return T(BitWidth);140 uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));141 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug142 return T(Mem, BitWidth);143 }144 145 Floating allocFloat(const llvm::fltSemantics &Sem) {146 if (Floating::singleWord(Sem))147 return Floating(llvm::APFloatBase::SemanticsToEnum(Sem));148 149 unsigned NumWords =150 APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem));151 uint64_t *Mem = (uint64_t *)this->allocate(NumWords * sizeof(uint64_t));152 // std::memset(Mem, 0, NumWords * sizeof(uint64_t)); // Debug153 return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem));154 }155 156private:157 friend class EvaluationResult;158 friend class InterpStateCCOverride;159 /// AST Walker state.160 State &Parent;161 /// Dead block chain.162 DeadBlock *DeadBlocks = nullptr;163 /// Reference to the offset-source mapping.164 SourceMapper *M;165 /// Allocator used for dynamic allocations performed via the program.166 std::unique_ptr<DynamicAllocator> Alloc;167 168public:169 /// Reference to the module containing all bytecode.170 Program &P;171 /// Temporary stack.172 InterpStack &Stk;173 /// Interpreter Context.174 Context &Ctx;175 /// Bottom function frame.176 InterpFrame BottomFrame;177 /// The current frame.178 InterpFrame *Current = nullptr;179 /// Source location of the evaluating expression180 SourceLocation EvalLocation;181 /// Declaration we're initializing/evaluting, if any.182 const VarDecl *EvaluatingDecl = nullptr;183 /// Things needed to do speculative execution.184 SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr;185 unsigned SpeculationDepth = 0;186 std::optional<bool> ConstantContextOverride;187 188 llvm::SmallVector<189 std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>190 SeenGlobalTemporaries;191 192 /// List of blocks we're currently running either constructors or destructors193 /// for.194 llvm::SmallVector<const Block *> InitializingBlocks;195 196 mutable std::optional<llvm::BumpPtrAllocator> Allocator;197};198 199class InterpStateCCOverride final {200public:201 InterpStateCCOverride(InterpState &Ctx, bool Value)202 : Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) {203 // We only override this if the new value is true.204 Enabled = Value;205 if (Enabled)206 Ctx.ConstantContextOverride = Value;207 }208 ~InterpStateCCOverride() {209 if (Enabled)210 Ctx.ConstantContextOverride = OldCC;211 }212 213private:214 bool Enabled;215 InterpState &Ctx;216 std::optional<bool> OldCC;217};218 219} // namespace interp220} // namespace clang221 222#endif223