1 | //===--- EvalEmitter.cpp - 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 | #include "EvalEmitter.h" |
10 | #include "Context.h" |
11 | #include "IntegralAP.h" |
12 | #include "Interp.h" |
13 | #include "Opcode.h" |
14 | #include "clang/AST/DeclCXX.h" |
15 | |
16 | using namespace clang; |
17 | using namespace clang::interp; |
18 | |
19 | EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent, |
20 | InterpStack &Stk) |
21 | : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) { |
22 | // Create a dummy frame for the interpreter which does not have locals. |
23 | S.Current = |
24 | new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0); |
25 | } |
26 | |
27 | EvalEmitter::~EvalEmitter() { |
28 | for (auto &[K, V] : Locals) { |
29 | Block *B = reinterpret_cast<Block *>(V.get()); |
30 | if (B->isInitialized()) |
31 | B->invokeDtor(); |
32 | } |
33 | } |
34 | |
35 | EvaluationResult EvalEmitter::interpretExpr(const Expr *E, |
36 | bool ConvertResultToRValue) { |
37 | this->ConvertResultToRValue = ConvertResultToRValue; |
38 | EvalResult.setSource(E); |
39 | |
40 | if (!this->visitExpr(E)) { |
41 | // EvalResult may already have a result set, but something failed |
42 | // after that (e.g. evaluating destructors). |
43 | EvalResult.setInvalid(); |
44 | } |
45 | |
46 | return std::move(this->EvalResult); |
47 | } |
48 | |
49 | EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, |
50 | bool CheckFullyInitialized) { |
51 | this->CheckFullyInitialized = CheckFullyInitialized; |
52 | this->ConvertResultToRValue = |
53 | VD->getAnyInitializer() && |
54 | (VD->getAnyInitializer()->getType()->isAnyComplexType() || |
55 | VD->getAnyInitializer()->getType()->isVectorType()); |
56 | EvalResult.setSource(VD); |
57 | |
58 | if (!this->visitDecl(VD) && EvalResult.empty()) |
59 | EvalResult.setInvalid(); |
60 | |
61 | return std::move(this->EvalResult); |
62 | } |
63 | |
64 | void EvalEmitter::emitLabel(LabelTy Label) { |
65 | CurrentLabel = Label; |
66 | } |
67 | |
68 | EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } |
69 | |
70 | Scope::Local EvalEmitter::createLocal(Descriptor *D) { |
71 | // Allocate memory for a local. |
72 | auto Memory = std::make_unique<char[]>(num: sizeof(Block) + D->getAllocSize()); |
73 | auto *B = new (Memory.get()) Block(D, /*isStatic=*/false); |
74 | B->invokeCtor(); |
75 | |
76 | // Initialize local variable inline descriptor. |
77 | InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); |
78 | Desc.Desc = D; |
79 | Desc.Offset = sizeof(InlineDescriptor); |
80 | Desc.IsActive = true; |
81 | Desc.IsBase = false; |
82 | Desc.IsFieldMutable = false; |
83 | Desc.IsConst = false; |
84 | Desc.IsInitialized = false; |
85 | |
86 | // Register the local. |
87 | unsigned Off = Locals.size(); |
88 | Locals.insert(KV: {Off, std::move(Memory)}); |
89 | return {.Offset: Off, .Desc: D}; |
90 | } |
91 | |
92 | bool EvalEmitter::jumpTrue(const LabelTy &Label) { |
93 | if (isActive()) { |
94 | if (S.Stk.pop<bool>()) |
95 | ActiveLabel = Label; |
96 | } |
97 | return true; |
98 | } |
99 | |
100 | bool EvalEmitter::jumpFalse(const LabelTy &Label) { |
101 | if (isActive()) { |
102 | if (!S.Stk.pop<bool>()) |
103 | ActiveLabel = Label; |
104 | } |
105 | return true; |
106 | } |
107 | |
108 | bool EvalEmitter::jump(const LabelTy &Label) { |
109 | if (isActive()) |
110 | CurrentLabel = ActiveLabel = Label; |
111 | return true; |
112 | } |
113 | |
114 | bool EvalEmitter::fallthrough(const LabelTy &Label) { |
115 | if (isActive()) |
116 | ActiveLabel = Label; |
117 | CurrentLabel = Label; |
118 | return true; |
119 | } |
120 | |
121 | template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) { |
122 | if (!isActive()) |
123 | return true; |
124 | using T = typename PrimConv<OpType>::T; |
125 | EvalResult.setValue(S.Stk.pop<T>().toAPValue()); |
126 | return true; |
127 | } |
128 | |
129 | template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { |
130 | if (!isActive()) |
131 | return true; |
132 | |
133 | const Pointer &Ptr = S.Stk.pop<Pointer>(); |
134 | // Implicitly convert lvalue to rvalue, if requested. |
135 | if (ConvertResultToRValue) { |
136 | if (std::optional<APValue> V = Ptr.toRValue(Ctx)) { |
137 | EvalResult.setValue(*V); |
138 | } else { |
139 | return false; |
140 | } |
141 | } else { |
142 | if (CheckFullyInitialized) { |
143 | if (!EvalResult.checkFullyInitialized(S, Ptr)) |
144 | return false; |
145 | |
146 | std::optional<APValue> RValueResult = Ptr.toRValue(Ctx); |
147 | if (!RValueResult) |
148 | return false; |
149 | EvalResult.setValue(*RValueResult); |
150 | } else { |
151 | EvalResult.setValue(Ptr.toAPValue()); |
152 | } |
153 | } |
154 | |
155 | return true; |
156 | } |
157 | template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) { |
158 | if (!isActive()) |
159 | return true; |
160 | // Function pointers cannot be converted to rvalues. |
161 | EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>()); |
162 | return true; |
163 | } |
164 | |
165 | bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { |
166 | EvalResult.setValid(); |
167 | return true; |
168 | } |
169 | |
170 | bool EvalEmitter::emitRetValue(const SourceInfo &Info) { |
171 | const auto &Ptr = S.Stk.pop<Pointer>(); |
172 | if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) { |
173 | EvalResult.setValue(*APV); |
174 | return true; |
175 | } |
176 | |
177 | EvalResult.setInvalid(); |
178 | return false; |
179 | } |
180 | |
181 | bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) { |
182 | if (!isActive()) |
183 | return true; |
184 | |
185 | Block *B = getLocal(Index: I); |
186 | S.Stk.push<Pointer>(Args&: B, Args: sizeof(InlineDescriptor)); |
187 | return true; |
188 | } |
189 | |
190 | template <PrimType OpType> |
191 | bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { |
192 | if (!isActive()) |
193 | return true; |
194 | |
195 | using T = typename PrimConv<OpType>::T; |
196 | |
197 | Block *B = getLocal(Index: I); |
198 | S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); |
199 | return true; |
200 | } |
201 | |
202 | template <PrimType OpType> |
203 | bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) { |
204 | if (!isActive()) |
205 | return true; |
206 | |
207 | using T = typename PrimConv<OpType>::T; |
208 | |
209 | Block *B = getLocal(Index: I); |
210 | *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>(); |
211 | InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); |
212 | Desc.IsInitialized = true; |
213 | |
214 | return true; |
215 | } |
216 | |
217 | bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) { |
218 | if (!isActive()) |
219 | return true; |
220 | |
221 | for (auto &Local : Descriptors[I]) { |
222 | Block *B = getLocal(Index: Local.Offset); |
223 | S.deallocate(B); |
224 | } |
225 | |
226 | return true; |
227 | } |
228 | |
229 | //===----------------------------------------------------------------------===// |
230 | // Opcode evaluators |
231 | //===----------------------------------------------------------------------===// |
232 | |
233 | #define GET_EVAL_IMPL |
234 | #include "Opcodes.inc" |
235 | #undef GET_EVAL_IMPL |
236 | |