1//===--- EvalEmitter.h - Instruction emitter for the 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// Defines the instruction emitters.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_EVALEMITTER_H
14#define LLVM_CLANG_AST_INTERP_EVALEMITTER_H
15
16#include "EvaluationResult.h"
17#include "InterpState.h"
18#include "PrimType.h"
19#include "Record.h"
20#include "Source.h"
21
22namespace clang {
23namespace interp {
24class Context;
25class Function;
26class InterpStack;
27class FrameAllocator;
28class Program;
29enum Opcode : uint32_t;
30
31/// An emitter which evaluates opcodes as they are emitted.
32class EvalEmitter : public SourceMapper {
33public:
34 using LabelTy = uint32_t;
35 using AddrTy = uintptr_t;
36 using Local = Scope::Local;
37 using PtrCallback =
38 llvm::function_ref<bool(InterpState &S, CodePtr OpPC, const Pointer &)>;
39
40 EvaluationResult interpretExpr(const Expr *E) {
41 return interpretExpr(E, /*ConvertResultToRValue=*/ConvertResultToRValue: E->isGLValue(),
42 /*DestroyToplevelScope=*/DestroyToplevelScope: false);
43 }
44
45 EvaluationResult interpretExpr(const Expr *E, bool ConvertResultToRValue,
46 bool DestroyToplevelScope = false);
47
48 EvaluationResult interpretDecl(const VarDecl *VD, const Expr *Init,
49 bool CheckFullyInitialized);
50 EvaluationResult interpretDestructor(const VarDecl *VD, const APValue &Value);
51 /// Interpret the given Expr to a Pointer.
52 EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB);
53 EvaluationResult interpretAsLValuePointer(const Expr *E, PtrCallback PtrCB);
54 /// Interpret the given expression as if it was in the body of the given
55 /// function, i.e. the parameters of the function are available for use.
56 bool interpretCall(const FunctionDecl *FD, const Expr *E);
57
58 std::optional<bool> interpretWithSubstitutions(const FunctionDecl *Callee,
59 ArrayRef<const Expr *> Args,
60 const Expr *This,
61 const Expr *Condition);
62
63 /// Clean up all resources.
64 void cleanup();
65
66 /// Returns the source location of the current opcode.
67 SourceInfo getSource(CodePtr PC) const override { return CurrentSource; }
68
69 bool constantFolding() const {
70 return S.EvalMode == EvaluationMode::ConstantFold;
71 }
72
73protected:
74 EvalEmitter(Context &Ctx, Program &P, const EvalSettings &Settings,
75 InterpStack &Stk, FrameAllocator &FrameAlloc);
76
77 EvalEmitter(Context &Ctx, Program &P, Expr::EvalStatus &Status,
78 InterpStack &Stk, FrameAllocator &FrameAlloc);
79
80 /// Define a label.
81 void emitLabel(LabelTy Label);
82 /// Create a label.
83 LabelTy getLabel();
84
85 /// Methods implemented by the compiler.
86 virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0;
87 virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) = 0;
88 virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
89 bool ConstantContext) = 0;
90 virtual bool visitDtorCall(const VarDecl *VD, const APValue &Value) = 0;
91 virtual bool visitWithSubstitutions(const FunctionDecl *Callee,
92 ArrayRef<const Expr *> Args,
93 const Expr *This,
94 const Expr *Condition) = 0;
95 virtual bool visitFunc(const FunctionDecl *F) = 0;
96 virtual bool visit(const Expr *E) = 0;
97 virtual bool emitBool(bool V, const Expr *E) = 0;
98
99 /// Emits jumps.
100 bool jumpTrue(const LabelTy &Label, SourceInfo SI);
101 bool jumpFalse(const LabelTy &Label, SourceInfo SI);
102 bool jump(const LabelTy &Label, SourceInfo SI);
103 bool fallthrough(const LabelTy &Label);
104 /// Speculative execution.
105 bool speculate(const CallExpr *E, const LabelTy &EndLabel);
106
107 /// Since expressions can only jump forward, predicated execution is
108 /// used to deal with if-else statements.
109 bool isActive() const { return CurrentLabel == ActiveLabel; }
110 bool checkingForUndefinedBehavior() const {
111 return S.checkingForUndefinedBehavior();
112 }
113
114 /// Callback for registering a local.
115 Local createLocal(const Descriptor *D);
116
117 /// Parameter indices.
118 llvm::DenseMap<const ParmVarDecl *, FuncParam> Params;
119 /// Local descriptors.
120 llvm::SmallVector<SmallVector<Local, 2>, 1> Descriptors;
121 std::optional<SourceInfo> LocOverride = std::nullopt;
122
123private:
124 /// Current compilation context.
125 Context &Ctx;
126 /// Current program.
127 Program &P;
128 /// Callee evaluation state.
129 InterpState S;
130 /// Location to write the result to.
131 EvaluationResult EvalResult;
132 ConstantExprKind ConstexprKind = ConstantExprKind::Normal;
133 /// Whether the result should be converted to an RValue.
134 bool ConvertResultToRValue = false;
135 /// Whether we should check if the result has been fully
136 /// initialized.
137 bool CheckFullyInitialized = false;
138 /// Callback to call when using interpretAsPointer.
139 std::optional<PtrCallback> PtrCB;
140
141 /// Temporaries which require storage.
142 llvm::SmallVector<char *> Locals;
143
144 Block *getLocal(unsigned Index) const {
145 assert(Index < Locals.size());
146 return reinterpret_cast<Block *>(Locals[Index]);
147 }
148
149 void updateGlobalTemporaries();
150
151 /// Location of the current instruction.
152 SourceInfo CurrentSource;
153
154 /// Next label ID to generate - first label is 1.
155 LabelTy NextLabel = 1;
156 /// Label being executed - 0 is the entry label.
157 LabelTy CurrentLabel = 0;
158 /// Active block which should be executed.
159 LabelTy ActiveLabel = 0;
160
161protected:
162#define GET_EVAL_PROTO
163#include "Opcodes.inc"
164#undef GET_EVAL_PROTO
165};
166
167} // namespace interp
168} // namespace clang
169
170#endif
171