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