xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.cpp (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
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 
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 
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 
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 
45 void EvalEmitter::emitLabel(LabelTy Label) {
46   CurrentLabel = Label;
47 }
48 
49 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
50 
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 
63 bool EvalEmitter::bail(const SourceLocation &Loc) {
64   if (!BailLocation)
65     BailLocation = Loc;
66   return false;
67 }
68 
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 
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 
85 bool EvalEmitter::jump(const LabelTy &Label) {
86   if (isActive())
87     CurrentLabel = ActiveLabel = Label;
88   return true;
89 }
90 
91 bool EvalEmitter::fallthrough(const LabelTy &Label) {
92   if (isActive())
93     ActiveLabel = Label;
94   CurrentLabel = Label;
95   return true;
96 }
97 
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 
105 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
106 
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 
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>
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>
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 
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