1*700637cbSDimitry Andric //===--- EvalEmitter.cpp - Instruction emitter for the VM -------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric
9*700637cbSDimitry Andric #include "EvalEmitter.h"
10*700637cbSDimitry Andric #include "Context.h"
11*700637cbSDimitry Andric #include "IntegralAP.h"
12*700637cbSDimitry Andric #include "Interp.h"
13*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h"
14*700637cbSDimitry Andric
15*700637cbSDimitry Andric using namespace clang;
16*700637cbSDimitry Andric using namespace clang::interp;
17*700637cbSDimitry Andric
EvalEmitter(Context & Ctx,Program & P,State & Parent,InterpStack & Stk)18*700637cbSDimitry Andric EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
19*700637cbSDimitry Andric InterpStack &Stk)
20*700637cbSDimitry Andric : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {}
21*700637cbSDimitry Andric
~EvalEmitter()22*700637cbSDimitry Andric EvalEmitter::~EvalEmitter() {
23*700637cbSDimitry Andric for (auto &V : Locals) {
24*700637cbSDimitry Andric Block *B = reinterpret_cast<Block *>(V.get());
25*700637cbSDimitry Andric if (B->isInitialized())
26*700637cbSDimitry Andric B->invokeDtor();
27*700637cbSDimitry Andric }
28*700637cbSDimitry Andric }
29*700637cbSDimitry Andric
30*700637cbSDimitry Andric /// Clean up all our resources. This needs to done in failed evaluations before
31*700637cbSDimitry Andric /// we call InterpStack::clear(), because there might be a Pointer on the stack
32*700637cbSDimitry Andric /// pointing into a Block in the EvalEmitter.
cleanup()33*700637cbSDimitry Andric void EvalEmitter::cleanup() { S.cleanup(); }
34*700637cbSDimitry Andric
interpretExpr(const Expr * E,bool ConvertResultToRValue,bool DestroyToplevelScope)35*700637cbSDimitry Andric EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
36*700637cbSDimitry Andric bool ConvertResultToRValue,
37*700637cbSDimitry Andric bool DestroyToplevelScope) {
38*700637cbSDimitry Andric S.setEvalLocation(E->getExprLoc());
39*700637cbSDimitry Andric this->ConvertResultToRValue = ConvertResultToRValue && !isa<ConstantExpr>(E);
40*700637cbSDimitry Andric this->CheckFullyInitialized = isa<ConstantExpr>(E);
41*700637cbSDimitry Andric EvalResult.setSource(E);
42*700637cbSDimitry Andric
43*700637cbSDimitry Andric if (!this->visitExpr(E, DestroyToplevelScope)) {
44*700637cbSDimitry Andric // EvalResult may already have a result set, but something failed
45*700637cbSDimitry Andric // after that (e.g. evaluating destructors).
46*700637cbSDimitry Andric EvalResult.setInvalid();
47*700637cbSDimitry Andric }
48*700637cbSDimitry Andric
49*700637cbSDimitry Andric return std::move(this->EvalResult);
50*700637cbSDimitry Andric }
51*700637cbSDimitry Andric
interpretDecl(const VarDecl * VD,bool CheckFullyInitialized)52*700637cbSDimitry Andric EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
53*700637cbSDimitry Andric bool CheckFullyInitialized) {
54*700637cbSDimitry Andric this->CheckFullyInitialized = CheckFullyInitialized;
55*700637cbSDimitry Andric S.EvaluatingDecl = VD;
56*700637cbSDimitry Andric EvalResult.setSource(VD);
57*700637cbSDimitry Andric
58*700637cbSDimitry Andric if (const Expr *Init = VD->getAnyInitializer()) {
59*700637cbSDimitry Andric QualType T = VD->getType();
60*700637cbSDimitry Andric this->ConvertResultToRValue = !Init->isGLValue() && !T->isPointerType() &&
61*700637cbSDimitry Andric !T->isObjCObjectPointerType();
62*700637cbSDimitry Andric } else
63*700637cbSDimitry Andric this->ConvertResultToRValue = false;
64*700637cbSDimitry Andric
65*700637cbSDimitry Andric EvalResult.setSource(VD);
66*700637cbSDimitry Andric
67*700637cbSDimitry Andric if (!this->visitDeclAndReturn(VD, S.inConstantContext()))
68*700637cbSDimitry Andric EvalResult.setInvalid();
69*700637cbSDimitry Andric
70*700637cbSDimitry Andric S.EvaluatingDecl = nullptr;
71*700637cbSDimitry Andric updateGlobalTemporaries();
72*700637cbSDimitry Andric return std::move(this->EvalResult);
73*700637cbSDimitry Andric }
74*700637cbSDimitry Andric
interpretAsPointer(const Expr * E,PtrCallback PtrCB)75*700637cbSDimitry Andric EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E,
76*700637cbSDimitry Andric PtrCallback PtrCB) {
77*700637cbSDimitry Andric
78*700637cbSDimitry Andric S.setEvalLocation(E->getExprLoc());
79*700637cbSDimitry Andric this->ConvertResultToRValue = false;
80*700637cbSDimitry Andric this->CheckFullyInitialized = false;
81*700637cbSDimitry Andric this->PtrCB = PtrCB;
82*700637cbSDimitry Andric EvalResult.setSource(E);
83*700637cbSDimitry Andric
84*700637cbSDimitry Andric if (!this->visitExpr(E, /*DestroyToplevelScope=*/true)) {
85*700637cbSDimitry Andric // EvalResult may already have a result set, but something failed
86*700637cbSDimitry Andric // after that (e.g. evaluating destructors).
87*700637cbSDimitry Andric EvalResult.setInvalid();
88*700637cbSDimitry Andric }
89*700637cbSDimitry Andric
90*700637cbSDimitry Andric return std::move(this->EvalResult);
91*700637cbSDimitry Andric }
92*700637cbSDimitry Andric
emitLabel(LabelTy Label)93*700637cbSDimitry Andric void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; }
94*700637cbSDimitry Andric
getLabel()95*700637cbSDimitry Andric EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
96*700637cbSDimitry Andric
createLocal(Descriptor * D)97*700637cbSDimitry Andric Scope::Local EvalEmitter::createLocal(Descriptor *D) {
98*700637cbSDimitry Andric // Allocate memory for a local.
99*700637cbSDimitry Andric auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
100*700637cbSDimitry Andric auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, /*isStatic=*/false);
101*700637cbSDimitry Andric B->invokeCtor();
102*700637cbSDimitry Andric
103*700637cbSDimitry Andric // Initialize local variable inline descriptor.
104*700637cbSDimitry Andric InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
105*700637cbSDimitry Andric Desc.Desc = D;
106*700637cbSDimitry Andric Desc.Offset = sizeof(InlineDescriptor);
107*700637cbSDimitry Andric Desc.IsActive = true;
108*700637cbSDimitry Andric Desc.IsBase = false;
109*700637cbSDimitry Andric Desc.IsFieldMutable = false;
110*700637cbSDimitry Andric Desc.IsConst = false;
111*700637cbSDimitry Andric Desc.IsInitialized = false;
112*700637cbSDimitry Andric
113*700637cbSDimitry Andric // Register the local.
114*700637cbSDimitry Andric unsigned Off = Locals.size();
115*700637cbSDimitry Andric Locals.push_back(std::move(Memory));
116*700637cbSDimitry Andric return {Off, D};
117*700637cbSDimitry Andric }
118*700637cbSDimitry Andric
jumpTrue(const LabelTy & Label)119*700637cbSDimitry Andric bool EvalEmitter::jumpTrue(const LabelTy &Label) {
120*700637cbSDimitry Andric if (isActive()) {
121*700637cbSDimitry Andric if (S.Stk.pop<bool>())
122*700637cbSDimitry Andric ActiveLabel = Label;
123*700637cbSDimitry Andric }
124*700637cbSDimitry Andric return true;
125*700637cbSDimitry Andric }
126*700637cbSDimitry Andric
jumpFalse(const LabelTy & Label)127*700637cbSDimitry Andric bool EvalEmitter::jumpFalse(const LabelTy &Label) {
128*700637cbSDimitry Andric if (isActive()) {
129*700637cbSDimitry Andric if (!S.Stk.pop<bool>())
130*700637cbSDimitry Andric ActiveLabel = Label;
131*700637cbSDimitry Andric }
132*700637cbSDimitry Andric return true;
133*700637cbSDimitry Andric }
134*700637cbSDimitry Andric
jump(const LabelTy & Label)135*700637cbSDimitry Andric bool EvalEmitter::jump(const LabelTy &Label) {
136*700637cbSDimitry Andric if (isActive())
137*700637cbSDimitry Andric CurrentLabel = ActiveLabel = Label;
138*700637cbSDimitry Andric return true;
139*700637cbSDimitry Andric }
140*700637cbSDimitry Andric
fallthrough(const LabelTy & Label)141*700637cbSDimitry Andric bool EvalEmitter::fallthrough(const LabelTy &Label) {
142*700637cbSDimitry Andric if (isActive())
143*700637cbSDimitry Andric ActiveLabel = Label;
144*700637cbSDimitry Andric CurrentLabel = Label;
145*700637cbSDimitry Andric return true;
146*700637cbSDimitry Andric }
147*700637cbSDimitry Andric
speculate(const CallExpr * E,const LabelTy & EndLabel)148*700637cbSDimitry Andric bool EvalEmitter::speculate(const CallExpr *E, const LabelTy &EndLabel) {
149*700637cbSDimitry Andric size_t StackSizeBefore = S.Stk.size();
150*700637cbSDimitry Andric const Expr *Arg = E->getArg(0);
151*700637cbSDimitry Andric if (!this->visit(Arg)) {
152*700637cbSDimitry Andric S.Stk.clearTo(StackSizeBefore);
153*700637cbSDimitry Andric
154*700637cbSDimitry Andric if (S.inConstantContext() || Arg->HasSideEffects(S.getASTContext()))
155*700637cbSDimitry Andric return this->emitBool(false, E);
156*700637cbSDimitry Andric return Invalid(S, OpPC);
157*700637cbSDimitry Andric }
158*700637cbSDimitry Andric
159*700637cbSDimitry Andric PrimType T = Ctx.classify(Arg->getType()).value_or(PT_Ptr);
160*700637cbSDimitry Andric if (T == PT_Ptr) {
161*700637cbSDimitry Andric const auto &Ptr = S.Stk.pop<Pointer>();
162*700637cbSDimitry Andric return this->emitBool(CheckBCPResult(S, Ptr), E);
163*700637cbSDimitry Andric }
164*700637cbSDimitry Andric
165*700637cbSDimitry Andric // Otherwise, this is fine!
166*700637cbSDimitry Andric if (!this->emitPop(T, E))
167*700637cbSDimitry Andric return false;
168*700637cbSDimitry Andric return this->emitBool(true, E);
169*700637cbSDimitry Andric }
170*700637cbSDimitry Andric
emitRet(const SourceInfo & Info)171*700637cbSDimitry Andric template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
172*700637cbSDimitry Andric if (!isActive())
173*700637cbSDimitry Andric return true;
174*700637cbSDimitry Andric
175*700637cbSDimitry Andric using T = typename PrimConv<OpType>::T;
176*700637cbSDimitry Andric EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
177*700637cbSDimitry Andric return true;
178*700637cbSDimitry Andric }
179*700637cbSDimitry Andric
emitRet(const SourceInfo & Info)180*700637cbSDimitry Andric template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
181*700637cbSDimitry Andric if (!isActive())
182*700637cbSDimitry Andric return true;
183*700637cbSDimitry Andric
184*700637cbSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>();
185*700637cbSDimitry Andric
186*700637cbSDimitry Andric if (Ptr.isFunctionPointer()) {
187*700637cbSDimitry Andric EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
188*700637cbSDimitry Andric return true;
189*700637cbSDimitry Andric }
190*700637cbSDimitry Andric
191*700637cbSDimitry Andric // If we're returning a raw pointer, call our callback.
192*700637cbSDimitry Andric if (this->PtrCB)
193*700637cbSDimitry Andric return (*this->PtrCB)(Ptr);
194*700637cbSDimitry Andric
195*700637cbSDimitry Andric if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))
196*700637cbSDimitry Andric return false;
197*700637cbSDimitry Andric if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
198*700637cbSDimitry Andric return false;
199*700637cbSDimitry Andric
200*700637cbSDimitry Andric // Implicitly convert lvalue to rvalue, if requested.
201*700637cbSDimitry Andric if (ConvertResultToRValue) {
202*700637cbSDimitry Andric if (!Ptr.isZero() && !Ptr.isDereferencable())
203*700637cbSDimitry Andric return false;
204*700637cbSDimitry Andric
205*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus11 && Ptr.isBlockPointer() &&
206*700637cbSDimitry Andric !CheckFinalLoad(S, OpPC, Ptr)) {
207*700637cbSDimitry Andric return false;
208*700637cbSDimitry Andric }
209*700637cbSDimitry Andric
210*700637cbSDimitry Andric // Never allow reading from a non-const pointer, unless the memory
211*700637cbSDimitry Andric // has been created in this evaluation.
212*700637cbSDimitry Andric if (!Ptr.isZero() && !Ptr.isConst() && Ptr.isBlockPointer() &&
213*700637cbSDimitry Andric Ptr.block()->getEvalID() != Ctx.getEvalID())
214*700637cbSDimitry Andric return false;
215*700637cbSDimitry Andric
216*700637cbSDimitry Andric if (std::optional<APValue> V =
217*700637cbSDimitry Andric Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
218*700637cbSDimitry Andric EvalResult.setValue(*V);
219*700637cbSDimitry Andric } else {
220*700637cbSDimitry Andric return false;
221*700637cbSDimitry Andric }
222*700637cbSDimitry Andric } else {
223*700637cbSDimitry Andric if (!Ptr.isLive() && !Ptr.isTemporary())
224*700637cbSDimitry Andric return false;
225*700637cbSDimitry Andric
226*700637cbSDimitry Andric EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
227*700637cbSDimitry Andric }
228*700637cbSDimitry Andric
229*700637cbSDimitry Andric return true;
230*700637cbSDimitry Andric }
231*700637cbSDimitry Andric
emitRetVoid(const SourceInfo & Info)232*700637cbSDimitry Andric bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
233*700637cbSDimitry Andric EvalResult.setValid();
234*700637cbSDimitry Andric return true;
235*700637cbSDimitry Andric }
236*700637cbSDimitry Andric
emitRetValue(const SourceInfo & Info)237*700637cbSDimitry Andric bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
238*700637cbSDimitry Andric const auto &Ptr = S.Stk.pop<Pointer>();
239*700637cbSDimitry Andric
240*700637cbSDimitry Andric if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))
241*700637cbSDimitry Andric return false;
242*700637cbSDimitry Andric if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
243*700637cbSDimitry Andric return false;
244*700637cbSDimitry Andric
245*700637cbSDimitry Andric if (std::optional<APValue> APV =
246*700637cbSDimitry Andric Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
247*700637cbSDimitry Andric EvalResult.setValue(*APV);
248*700637cbSDimitry Andric return true;
249*700637cbSDimitry Andric }
250*700637cbSDimitry Andric
251*700637cbSDimitry Andric EvalResult.setInvalid();
252*700637cbSDimitry Andric return false;
253*700637cbSDimitry Andric }
254*700637cbSDimitry Andric
emitGetPtrLocal(uint32_t I,const SourceInfo & Info)255*700637cbSDimitry Andric bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
256*700637cbSDimitry Andric if (!isActive())
257*700637cbSDimitry Andric return true;
258*700637cbSDimitry Andric
259*700637cbSDimitry Andric Block *B = getLocal(I);
260*700637cbSDimitry Andric S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
261*700637cbSDimitry Andric return true;
262*700637cbSDimitry Andric }
263*700637cbSDimitry Andric
264*700637cbSDimitry Andric template <PrimType OpType>
emitGetLocal(uint32_t I,const SourceInfo & Info)265*700637cbSDimitry Andric bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
266*700637cbSDimitry Andric if (!isActive())
267*700637cbSDimitry Andric return true;
268*700637cbSDimitry Andric
269*700637cbSDimitry Andric using T = typename PrimConv<OpType>::T;
270*700637cbSDimitry Andric
271*700637cbSDimitry Andric Block *B = getLocal(I);
272*700637cbSDimitry Andric S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
273*700637cbSDimitry Andric return true;
274*700637cbSDimitry Andric }
275*700637cbSDimitry Andric
276*700637cbSDimitry Andric template <PrimType OpType>
emitSetLocal(uint32_t I,const SourceInfo & Info)277*700637cbSDimitry Andric bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
278*700637cbSDimitry Andric if (!isActive())
279*700637cbSDimitry Andric return true;
280*700637cbSDimitry Andric
281*700637cbSDimitry Andric using T = typename PrimConv<OpType>::T;
282*700637cbSDimitry Andric
283*700637cbSDimitry Andric Block *B = getLocal(I);
284*700637cbSDimitry Andric *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();
285*700637cbSDimitry Andric InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
286*700637cbSDimitry Andric Desc.IsInitialized = true;
287*700637cbSDimitry Andric
288*700637cbSDimitry Andric return true;
289*700637cbSDimitry Andric }
290*700637cbSDimitry Andric
emitDestroy(uint32_t I,const SourceInfo & Info)291*700637cbSDimitry Andric bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
292*700637cbSDimitry Andric if (!isActive())
293*700637cbSDimitry Andric return true;
294*700637cbSDimitry Andric
295*700637cbSDimitry Andric for (auto &Local : Descriptors[I]) {
296*700637cbSDimitry Andric Block *B = getLocal(Local.Offset);
297*700637cbSDimitry Andric S.deallocate(B);
298*700637cbSDimitry Andric }
299*700637cbSDimitry Andric
300*700637cbSDimitry Andric return true;
301*700637cbSDimitry Andric }
302*700637cbSDimitry Andric
303*700637cbSDimitry Andric /// Global temporaries (LifetimeExtendedTemporary) carry their value
304*700637cbSDimitry Andric /// around as an APValue, which codegen accesses.
305*700637cbSDimitry Andric /// We set their value once when creating them, but we don't update it
306*700637cbSDimitry Andric /// afterwards when code changes it later.
307*700637cbSDimitry Andric /// This is what we do here.
updateGlobalTemporaries()308*700637cbSDimitry Andric void EvalEmitter::updateGlobalTemporaries() {
309*700637cbSDimitry Andric for (const auto &[E, Temp] : S.SeenGlobalTemporaries) {
310*700637cbSDimitry Andric if (std::optional<unsigned> GlobalIndex = P.getGlobal(E)) {
311*700637cbSDimitry Andric const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);
312*700637cbSDimitry Andric APValue *Cached = Temp->getOrCreateValue(true);
313*700637cbSDimitry Andric
314*700637cbSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(E->getType())) {
315*700637cbSDimitry Andric TYPE_SWITCH(
316*700637cbSDimitry Andric *T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); });
317*700637cbSDimitry Andric } else {
318*700637cbSDimitry Andric if (std::optional<APValue> APV =
319*700637cbSDimitry Andric Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
320*700637cbSDimitry Andric *Cached = *APV;
321*700637cbSDimitry Andric }
322*700637cbSDimitry Andric }
323*700637cbSDimitry Andric }
324*700637cbSDimitry Andric S.SeenGlobalTemporaries.clear();
325*700637cbSDimitry Andric }
326*700637cbSDimitry Andric
327*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
328*700637cbSDimitry Andric // Opcode evaluators
329*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
330*700637cbSDimitry Andric
331*700637cbSDimitry Andric #define GET_EVAL_IMPL
332*700637cbSDimitry Andric #include "Opcodes.inc"
333*700637cbSDimitry Andric #undef GET_EVAL_IMPL
334