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 "Interp.h"
12 #include "Opcode.h"
13 #include "Program.h"
14 #include "clang/AST/DeclCXX.h"
15
16 using namespace clang;
17 using namespace clang::interp;
18
19 using APSInt = llvm::APSInt;
20 template <typename T> using Expected = llvm::Expected<T>;
21
EvalEmitter(Context & Ctx,Program & P,State & Parent,InterpStack & Stk,APValue & Result)22 EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
23 InterpStack &Stk, APValue &Result)
24 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), Result(Result) {
25 // Create a dummy frame for the interpreter which does not have locals.
26 S.Current = new InterpFrame(S, nullptr, nullptr, CodePtr(), Pointer());
27 }
28
interpretExpr(const Expr * E)29 llvm::Expected<bool> EvalEmitter::interpretExpr(const Expr *E) {
30 if (this->visitExpr(E))
31 return true;
32 if (BailLocation)
33 return llvm::make_error<ByteCodeGenError>(*BailLocation);
34 return false;
35 }
36
interpretDecl(const VarDecl * VD)37 llvm::Expected<bool> EvalEmitter::interpretDecl(const VarDecl *VD) {
38 if (this->visitDecl(VD))
39 return true;
40 if (BailLocation)
41 return llvm::make_error<ByteCodeGenError>(*BailLocation);
42 return false;
43 }
44
emitLabel(LabelTy Label)45 void EvalEmitter::emitLabel(LabelTy Label) {
46 CurrentLabel = Label;
47 }
48
getLabel()49 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
50
createLocal(Descriptor * D)51 Scope::Local EvalEmitter::createLocal(Descriptor *D) {
52 // Allocate memory for a local.
53 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
54 auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
55 B->invokeCtor();
56
57 // Register the local.
58 unsigned Off = Locals.size();
59 Locals.insert({Off, std::move(Memory)});
60 return {Off, D};
61 }
62
bail(const SourceLocation & Loc)63 bool EvalEmitter::bail(const SourceLocation &Loc) {
64 if (!BailLocation)
65 BailLocation = Loc;
66 return false;
67 }
68
jumpTrue(const LabelTy & Label)69 bool EvalEmitter::jumpTrue(const LabelTy &Label) {
70 if (isActive()) {
71 if (S.Stk.pop<bool>())
72 ActiveLabel = Label;
73 }
74 return true;
75 }
76
jumpFalse(const LabelTy & Label)77 bool EvalEmitter::jumpFalse(const LabelTy &Label) {
78 if (isActive()) {
79 if (!S.Stk.pop<bool>())
80 ActiveLabel = Label;
81 }
82 return true;
83 }
84
jump(const LabelTy & Label)85 bool EvalEmitter::jump(const LabelTy &Label) {
86 if (isActive())
87 CurrentLabel = ActiveLabel = Label;
88 return true;
89 }
90
fallthrough(const LabelTy & Label)91 bool EvalEmitter::fallthrough(const LabelTy &Label) {
92 if (isActive())
93 ActiveLabel = Label;
94 CurrentLabel = Label;
95 return true;
96 }
97
emitRet(const SourceInfo & Info)98 template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
99 if (!isActive())
100 return true;
101 using T = typename PrimConv<OpType>::T;
102 return ReturnValue<T>(S.Stk.pop<T>(), Result);
103 }
104
emitRetVoid(const SourceInfo & Info)105 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
106
emitRetValue(const SourceInfo & Info)107 bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
108 // Method to recursively traverse composites.
109 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
110 Composite = [this, &Composite](QualType Ty, const Pointer &Ptr, APValue &R) {
111 if (auto *AT = Ty->getAs<AtomicType>())
112 Ty = AT->getValueType();
113
114 if (auto *RT = Ty->getAs<RecordType>()) {
115 auto *Record = Ptr.getRecord();
116 assert(Record && "Missing record descriptor");
117
118 bool Ok = true;
119 if (RT->getDecl()->isUnion()) {
120 const FieldDecl *ActiveField = nullptr;
121 APValue Value;
122 for (auto &F : Record->fields()) {
123 const Pointer &FP = Ptr.atField(F.Offset);
124 QualType FieldTy = F.Decl->getType();
125 if (FP.isActive()) {
126 if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
127 TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
128 } else {
129 Ok &= Composite(FieldTy, FP, Value);
130 }
131 break;
132 }
133 }
134 R = APValue(ActiveField, Value);
135 } else {
136 unsigned NF = Record->getNumFields();
137 unsigned NB = Record->getNumBases();
138 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
139
140 R = APValue(APValue::UninitStruct(), NB, NF);
141
142 for (unsigned I = 0; I < NF; ++I) {
143 const Record::Field *FD = Record->getField(I);
144 QualType FieldTy = FD->Decl->getType();
145 const Pointer &FP = Ptr.atField(FD->Offset);
146 APValue &Value = R.getStructField(I);
147
148 if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
149 TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
150 } else {
151 Ok &= Composite(FieldTy, FP, Value);
152 }
153 }
154
155 for (unsigned I = 0; I < NB; ++I) {
156 const Record::Base *BD = Record->getBase(I);
157 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
158 const Pointer &BP = Ptr.atField(BD->Offset);
159 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
160 }
161
162 for (unsigned I = 0; I < NV; ++I) {
163 const Record::Base *VD = Record->getVirtualBase(I);
164 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
165 const Pointer &VP = Ptr.atField(VD->Offset);
166 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
167 }
168 }
169 return Ok;
170 }
171 if (auto *AT = Ty->getAsArrayTypeUnsafe()) {
172 const size_t NumElems = Ptr.getNumElems();
173 QualType ElemTy = AT->getElementType();
174 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
175
176 bool Ok = true;
177 for (unsigned I = 0; I < NumElems; ++I) {
178 APValue &Slot = R.getArrayInitializedElt(I);
179 const Pointer &EP = Ptr.atIndex(I);
180 if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
181 TYPE_SWITCH(*T, Ok &= ReturnValue<T>(EP.deref<T>(), Slot));
182 } else {
183 Ok &= Composite(ElemTy, EP.narrow(), Slot);
184 }
185 }
186 return Ok;
187 }
188 llvm_unreachable("invalid value to return");
189 };
190
191 // Return the composite type.
192 const auto &Ptr = S.Stk.pop<Pointer>();
193 return Composite(Ptr.getType(), Ptr, Result);
194 }
195
emitGetPtrLocal(uint32_t I,const SourceInfo & Info)196 bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
197 if (!isActive())
198 return true;
199
200 auto It = Locals.find(I);
201 assert(It != Locals.end() && "Missing local variable");
202 S.Stk.push<Pointer>(reinterpret_cast<Block *>(It->second.get()));
203 return true;
204 }
205
206 template <PrimType OpType>
emitGetLocal(uint32_t I,const SourceInfo & Info)207 bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
208 if (!isActive())
209 return true;
210
211 using T = typename PrimConv<OpType>::T;
212
213 auto It = Locals.find(I);
214 assert(It != Locals.end() && "Missing local variable");
215 auto *B = reinterpret_cast<Block *>(It->second.get());
216 S.Stk.push<T>(*reinterpret_cast<T *>(B + 1));
217 return true;
218 }
219
220 template <PrimType OpType>
emitSetLocal(uint32_t I,const SourceInfo & Info)221 bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
222 if (!isActive())
223 return true;
224
225 using T = typename PrimConv<OpType>::T;
226
227 auto It = Locals.find(I);
228 assert(It != Locals.end() && "Missing local variable");
229 auto *B = reinterpret_cast<Block *>(It->second.get());
230 *reinterpret_cast<T *>(B + 1) = S.Stk.pop<T>();
231 return true;
232 }
233
emitDestroy(uint32_t I,const SourceInfo & Info)234 bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
235 if (!isActive())
236 return true;
237
238 for (auto &Local : Descriptors[I]) {
239 auto It = Locals.find(Local.Offset);
240 assert(It != Locals.end() && "Missing local variable");
241 S.deallocate(reinterpret_cast<Block *>(It->second.get()));
242 }
243
244 return true;
245 }
246
247 //===----------------------------------------------------------------------===//
248 // Opcode evaluators
249 //===----------------------------------------------------------------------===//
250
251 #define GET_EVAL_IMPL
252 #include "Opcodes.inc"
253 #undef GET_EVAL_IMPL
254