xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1a7dea167SDimitry Andric //===--- EvalEmitter.cpp - Instruction emitter for the VM -------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric 
9a7dea167SDimitry Andric #include "EvalEmitter.h"
10a7dea167SDimitry Andric #include "Context.h"
115f757f3fSDimitry Andric #include "IntegralAP.h"
12a7dea167SDimitry Andric #include "Interp.h"
13a7dea167SDimitry Andric #include "Opcode.h"
14a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h"
15a7dea167SDimitry Andric 
16a7dea167SDimitry Andric using namespace clang;
17a7dea167SDimitry Andric using namespace clang::interp;
18a7dea167SDimitry Andric 
19a7dea167SDimitry Andric EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
20*0fca6ea1SDimitry Andric                          InterpStack &Stk)
217a6dacacSDimitry Andric     : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {
22a7dea167SDimitry Andric   // Create a dummy frame for the interpreter which does not have locals.
23bdd1243dSDimitry Andric   S.Current =
24*0fca6ea1SDimitry Andric       new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0);
25a7dea167SDimitry Andric }
26a7dea167SDimitry Andric 
275f757f3fSDimitry Andric EvalEmitter::~EvalEmitter() {
285f757f3fSDimitry Andric   for (auto &[K, V] : Locals) {
295f757f3fSDimitry Andric     Block *B = reinterpret_cast<Block *>(V.get());
305f757f3fSDimitry Andric     if (B->isInitialized())
315f757f3fSDimitry Andric       B->invokeDtor();
325f757f3fSDimitry Andric   }
335f757f3fSDimitry Andric }
345f757f3fSDimitry Andric 
35*0fca6ea1SDimitry Andric /// Clean up all our resources. This needs to done in failed evaluations before
36*0fca6ea1SDimitry Andric /// we call InterpStack::clear(), because there might be a Pointer on the stack
37*0fca6ea1SDimitry Andric /// pointing into a Block in the EvalEmitter.
38*0fca6ea1SDimitry Andric void EvalEmitter::cleanup() { S.cleanup(); }
39*0fca6ea1SDimitry Andric 
40*0fca6ea1SDimitry Andric EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
41*0fca6ea1SDimitry Andric                                             bool ConvertResultToRValue) {
42*0fca6ea1SDimitry Andric   S.setEvalLocation(E->getExprLoc());
43*0fca6ea1SDimitry Andric   this->ConvertResultToRValue = ConvertResultToRValue && !isa<ConstantExpr>(E);
44*0fca6ea1SDimitry Andric   this->CheckFullyInitialized = isa<ConstantExpr>(E);
457a6dacacSDimitry Andric   EvalResult.setSource(E);
467a6dacacSDimitry Andric 
47*0fca6ea1SDimitry Andric   if (!this->visitExpr(E)) {
48*0fca6ea1SDimitry Andric     // EvalResult may already have a result set, but something failed
49*0fca6ea1SDimitry Andric     // after that (e.g. evaluating destructors).
507a6dacacSDimitry Andric     EvalResult.setInvalid();
51*0fca6ea1SDimitry Andric   }
527a6dacacSDimitry Andric 
537a6dacacSDimitry Andric   return std::move(this->EvalResult);
54a7dea167SDimitry Andric }
55a7dea167SDimitry Andric 
56*0fca6ea1SDimitry Andric EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
57*0fca6ea1SDimitry Andric                                             bool CheckFullyInitialized) {
58*0fca6ea1SDimitry Andric   this->CheckFullyInitialized = CheckFullyInitialized;
59*0fca6ea1SDimitry Andric   S.EvaluatingDecl = VD;
607a6dacacSDimitry Andric   EvalResult.setSource(VD);
617a6dacacSDimitry Andric 
62*0fca6ea1SDimitry Andric   if (const Expr *Init = VD->getAnyInitializer()) {
63*0fca6ea1SDimitry Andric     QualType T = VD->getType();
64*0fca6ea1SDimitry Andric     this->ConvertResultToRValue = !Init->isGLValue() && !T->isPointerType() &&
65*0fca6ea1SDimitry Andric                                   !T->isObjCObjectPointerType();
66*0fca6ea1SDimitry Andric   } else
67*0fca6ea1SDimitry Andric     this->ConvertResultToRValue = false;
68*0fca6ea1SDimitry Andric 
69*0fca6ea1SDimitry Andric   EvalResult.setSource(VD);
70*0fca6ea1SDimitry Andric 
71*0fca6ea1SDimitry Andric   if (!this->visitDeclAndReturn(VD, S.inConstantContext()))
727a6dacacSDimitry Andric     EvalResult.setInvalid();
737a6dacacSDimitry Andric 
74*0fca6ea1SDimitry Andric   S.EvaluatingDecl = nullptr;
75*0fca6ea1SDimitry Andric   updateGlobalTemporaries();
767a6dacacSDimitry Andric   return std::move(this->EvalResult);
77a7dea167SDimitry Andric }
78a7dea167SDimitry Andric 
79a7dea167SDimitry Andric void EvalEmitter::emitLabel(LabelTy Label) {
80a7dea167SDimitry Andric   CurrentLabel = Label;
81a7dea167SDimitry Andric }
82a7dea167SDimitry Andric 
83a7dea167SDimitry Andric EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
84a7dea167SDimitry Andric 
85a7dea167SDimitry Andric Scope::Local EvalEmitter::createLocal(Descriptor *D) {
86a7dea167SDimitry Andric   // Allocate memory for a local.
87a7dea167SDimitry Andric   auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
88*0fca6ea1SDimitry Andric   auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, /*isStatic=*/false);
89a7dea167SDimitry Andric   B->invokeCtor();
90a7dea167SDimitry Andric 
91bdd1243dSDimitry Andric   // Initialize local variable inline descriptor.
92bdd1243dSDimitry Andric   InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
93bdd1243dSDimitry Andric   Desc.Desc = D;
94bdd1243dSDimitry Andric   Desc.Offset = sizeof(InlineDescriptor);
95bdd1243dSDimitry Andric   Desc.IsActive = true;
96bdd1243dSDimitry Andric   Desc.IsBase = false;
97bdd1243dSDimitry Andric   Desc.IsFieldMutable = false;
98bdd1243dSDimitry Andric   Desc.IsConst = false;
99bdd1243dSDimitry Andric   Desc.IsInitialized = false;
100bdd1243dSDimitry Andric 
101a7dea167SDimitry Andric   // Register the local.
102a7dea167SDimitry Andric   unsigned Off = Locals.size();
103a7dea167SDimitry Andric   Locals.insert({Off, std::move(Memory)});
104a7dea167SDimitry Andric   return {Off, D};
105a7dea167SDimitry Andric }
106a7dea167SDimitry Andric 
107a7dea167SDimitry Andric bool EvalEmitter::jumpTrue(const LabelTy &Label) {
108a7dea167SDimitry Andric   if (isActive()) {
109a7dea167SDimitry Andric     if (S.Stk.pop<bool>())
110a7dea167SDimitry Andric       ActiveLabel = Label;
111a7dea167SDimitry Andric   }
112a7dea167SDimitry Andric   return true;
113a7dea167SDimitry Andric }
114a7dea167SDimitry Andric 
115a7dea167SDimitry Andric bool EvalEmitter::jumpFalse(const LabelTy &Label) {
116a7dea167SDimitry Andric   if (isActive()) {
117a7dea167SDimitry Andric     if (!S.Stk.pop<bool>())
118a7dea167SDimitry Andric       ActiveLabel = Label;
119a7dea167SDimitry Andric   }
120a7dea167SDimitry Andric   return true;
121a7dea167SDimitry Andric }
122a7dea167SDimitry Andric 
123a7dea167SDimitry Andric bool EvalEmitter::jump(const LabelTy &Label) {
124a7dea167SDimitry Andric   if (isActive())
125a7dea167SDimitry Andric     CurrentLabel = ActiveLabel = Label;
126a7dea167SDimitry Andric   return true;
127a7dea167SDimitry Andric }
128a7dea167SDimitry Andric 
129a7dea167SDimitry Andric bool EvalEmitter::fallthrough(const LabelTy &Label) {
130a7dea167SDimitry Andric   if (isActive())
131a7dea167SDimitry Andric     ActiveLabel = Label;
132a7dea167SDimitry Andric   CurrentLabel = Label;
133a7dea167SDimitry Andric   return true;
134a7dea167SDimitry Andric }
135a7dea167SDimitry Andric 
136*0fca6ea1SDimitry Andric static bool checkReturnState(InterpState &S) {
137*0fca6ea1SDimitry Andric   return S.maybeDiagnoseDanglingAllocations();
138*0fca6ea1SDimitry Andric }
139*0fca6ea1SDimitry Andric 
140a7dea167SDimitry Andric template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
141a7dea167SDimitry Andric   if (!isActive())
142a7dea167SDimitry Andric     return true;
143*0fca6ea1SDimitry Andric 
144*0fca6ea1SDimitry Andric   if (!checkReturnState(S))
145*0fca6ea1SDimitry Andric     return false;
146*0fca6ea1SDimitry Andric 
147a7dea167SDimitry Andric   using T = typename PrimConv<OpType>::T;
148*0fca6ea1SDimitry Andric   EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
1497a6dacacSDimitry Andric   return true;
150a7dea167SDimitry Andric }
151a7dea167SDimitry Andric 
1527a6dacacSDimitry Andric template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
1537a6dacacSDimitry Andric   if (!isActive())
1547a6dacacSDimitry Andric     return true;
155*0fca6ea1SDimitry Andric 
156*0fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
157*0fca6ea1SDimitry Andric 
158*0fca6ea1SDimitry Andric   if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))
159*0fca6ea1SDimitry Andric     return false;
160*0fca6ea1SDimitry Andric   if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
161*0fca6ea1SDimitry Andric     return false;
162*0fca6ea1SDimitry Andric 
163*0fca6ea1SDimitry Andric   if (!checkReturnState(S))
164*0fca6ea1SDimitry Andric     return false;
165*0fca6ea1SDimitry Andric 
166*0fca6ea1SDimitry Andric   // Implicitly convert lvalue to rvalue, if requested.
167*0fca6ea1SDimitry Andric   if (ConvertResultToRValue) {
168*0fca6ea1SDimitry Andric     if (!Ptr.isZero() && !Ptr.isDereferencable())
169*0fca6ea1SDimitry Andric       return false;
170*0fca6ea1SDimitry Andric     // Never allow reading from a non-const pointer, unless the memory
171*0fca6ea1SDimitry Andric     // has been created in this evaluation.
172*0fca6ea1SDimitry Andric     if (!Ptr.isZero() && Ptr.isBlockPointer() &&
173*0fca6ea1SDimitry Andric         Ptr.block()->getEvalID() != Ctx.getEvalID() &&
174*0fca6ea1SDimitry Andric         (!CheckLoad(S, OpPC, Ptr, AK_Read) || !Ptr.isConst()))
175*0fca6ea1SDimitry Andric       return false;
176*0fca6ea1SDimitry Andric 
177*0fca6ea1SDimitry Andric     if (std::optional<APValue> V =
178*0fca6ea1SDimitry Andric             Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
179*0fca6ea1SDimitry Andric       EvalResult.setValue(*V);
180*0fca6ea1SDimitry Andric     } else {
181*0fca6ea1SDimitry Andric       return false;
182*0fca6ea1SDimitry Andric     }
183*0fca6ea1SDimitry Andric   } else {
184*0fca6ea1SDimitry Andric     EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
185*0fca6ea1SDimitry Andric   }
186*0fca6ea1SDimitry Andric 
1877a6dacacSDimitry Andric   return true;
1887a6dacacSDimitry Andric }
1897a6dacacSDimitry Andric template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
1907a6dacacSDimitry Andric   if (!isActive())
1917a6dacacSDimitry Andric     return true;
192*0fca6ea1SDimitry Andric 
193*0fca6ea1SDimitry Andric   if (!checkReturnState(S))
194*0fca6ea1SDimitry Andric     return false;
195*0fca6ea1SDimitry Andric   // Function pointers cannot be converted to rvalues.
1967a6dacacSDimitry Andric   EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
1977a6dacacSDimitry Andric   return true;
1987a6dacacSDimitry Andric }
1997a6dacacSDimitry Andric 
2007a6dacacSDimitry Andric bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
201*0fca6ea1SDimitry Andric   if (!checkReturnState(S))
202*0fca6ea1SDimitry Andric     return false;
2037a6dacacSDimitry Andric   EvalResult.setValid();
2047a6dacacSDimitry Andric   return true;
2057a6dacacSDimitry Andric }
206a7dea167SDimitry Andric 
207a7dea167SDimitry Andric bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
208a7dea167SDimitry Andric   const auto &Ptr = S.Stk.pop<Pointer>();
209*0fca6ea1SDimitry Andric 
210*0fca6ea1SDimitry Andric   if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))
211*0fca6ea1SDimitry Andric     return false;
212*0fca6ea1SDimitry Andric   if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
213*0fca6ea1SDimitry Andric     return false;
214*0fca6ea1SDimitry Andric 
215*0fca6ea1SDimitry Andric   if (!checkReturnState(S))
216*0fca6ea1SDimitry Andric     return false;
217*0fca6ea1SDimitry Andric 
218*0fca6ea1SDimitry Andric   if (std::optional<APValue> APV =
219*0fca6ea1SDimitry Andric           Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) {
2207a6dacacSDimitry Andric     EvalResult.setValue(*APV);
2217a6dacacSDimitry Andric     return true;
2227a6dacacSDimitry Andric   }
2237a6dacacSDimitry Andric 
2247a6dacacSDimitry Andric   EvalResult.setInvalid();
2257a6dacacSDimitry Andric   return false;
226a7dea167SDimitry Andric }
227a7dea167SDimitry Andric 
228a7dea167SDimitry Andric bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
229a7dea167SDimitry Andric   if (!isActive())
230a7dea167SDimitry Andric     return true;
231a7dea167SDimitry Andric 
23206c3fb27SDimitry Andric   Block *B = getLocal(I);
233bdd1243dSDimitry Andric   S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
234a7dea167SDimitry Andric   return true;
235a7dea167SDimitry Andric }
236a7dea167SDimitry Andric 
237a7dea167SDimitry Andric template <PrimType OpType>
238a7dea167SDimitry Andric bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
239a7dea167SDimitry Andric   if (!isActive())
240a7dea167SDimitry Andric     return true;
241a7dea167SDimitry Andric 
242a7dea167SDimitry Andric   using T = typename PrimConv<OpType>::T;
243a7dea167SDimitry Andric 
24406c3fb27SDimitry Andric   Block *B = getLocal(I);
245bdd1243dSDimitry Andric   S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
246a7dea167SDimitry Andric   return true;
247a7dea167SDimitry Andric }
248a7dea167SDimitry Andric 
249a7dea167SDimitry Andric template <PrimType OpType>
250a7dea167SDimitry Andric bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
251a7dea167SDimitry Andric   if (!isActive())
252a7dea167SDimitry Andric     return true;
253a7dea167SDimitry Andric 
254a7dea167SDimitry Andric   using T = typename PrimConv<OpType>::T;
255a7dea167SDimitry Andric 
25606c3fb27SDimitry Andric   Block *B = getLocal(I);
257bdd1243dSDimitry Andric   *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();
258bdd1243dSDimitry Andric   InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
259bdd1243dSDimitry Andric   Desc.IsInitialized = true;
260bdd1243dSDimitry Andric 
261a7dea167SDimitry Andric   return true;
262a7dea167SDimitry Andric }
263a7dea167SDimitry Andric 
264a7dea167SDimitry Andric bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
265a7dea167SDimitry Andric   if (!isActive())
266a7dea167SDimitry Andric     return true;
267a7dea167SDimitry Andric 
268a7dea167SDimitry Andric   for (auto &Local : Descriptors[I]) {
26906c3fb27SDimitry Andric     Block *B = getLocal(Local.Offset);
27006c3fb27SDimitry Andric     S.deallocate(B);
271a7dea167SDimitry Andric   }
272a7dea167SDimitry Andric 
273a7dea167SDimitry Andric   return true;
274a7dea167SDimitry Andric }
275a7dea167SDimitry Andric 
276*0fca6ea1SDimitry Andric /// Global temporaries (LifetimeExtendedTemporary) carry their value
277*0fca6ea1SDimitry Andric /// around as an APValue, which codegen accesses.
278*0fca6ea1SDimitry Andric /// We set their value once when creating them, but we don't update it
279*0fca6ea1SDimitry Andric /// afterwards when code changes it later.
280*0fca6ea1SDimitry Andric /// This is what we do here.
281*0fca6ea1SDimitry Andric void EvalEmitter::updateGlobalTemporaries() {
282*0fca6ea1SDimitry Andric   for (const auto &[E, Temp] : S.SeenGlobalTemporaries) {
283*0fca6ea1SDimitry Andric     if (std::optional<unsigned> GlobalIndex = P.getGlobal(E)) {
284*0fca6ea1SDimitry Andric       const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);
285*0fca6ea1SDimitry Andric       APValue *Cached = Temp->getOrCreateValue(true);
286*0fca6ea1SDimitry Andric 
287*0fca6ea1SDimitry Andric       if (std::optional<PrimType> T = Ctx.classify(E->getType())) {
288*0fca6ea1SDimitry Andric         TYPE_SWITCH(
289*0fca6ea1SDimitry Andric             *T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); });
290*0fca6ea1SDimitry Andric       } else {
291*0fca6ea1SDimitry Andric         if (std::optional<APValue> APV =
292*0fca6ea1SDimitry Andric                 Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
293*0fca6ea1SDimitry Andric           *Cached = *APV;
294*0fca6ea1SDimitry Andric       }
295*0fca6ea1SDimitry Andric     }
296*0fca6ea1SDimitry Andric   }
297*0fca6ea1SDimitry Andric   S.SeenGlobalTemporaries.clear();
298*0fca6ea1SDimitry Andric }
299*0fca6ea1SDimitry Andric 
300a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
301a7dea167SDimitry Andric // Opcode evaluators
302a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
303a7dea167SDimitry Andric 
304a7dea167SDimitry Andric #define GET_EVAL_IMPL
305a7dea167SDimitry Andric #include "Opcodes.inc"
306a7dea167SDimitry Andric #undef GET_EVAL_IMPL
307