EvalEmitter.cpp revision 360784
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
16using namespace clang;
17using namespace clang::interp;
18
19using APSInt = llvm::APSInt;
20template <typename T> using Expected = llvm::Expected<T>;
21
22EvalEmitter::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
29llvm::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
37llvm::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
45void EvalEmitter::emitLabel(LabelTy Label) {
46  CurrentLabel = Label;
47}
48
49EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
50
51Scope::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
63bool EvalEmitter::bail(const SourceLocation &Loc) {
64  if (!BailLocation)
65    BailLocation = Loc;
66  return false;
67}
68
69bool EvalEmitter::jumpTrue(const LabelTy &Label) {
70  if (isActive()) {
71    if (S.Stk.pop<bool>())
72      ActiveLabel = Label;
73  }
74  return true;
75}
76
77bool EvalEmitter::jumpFalse(const LabelTy &Label) {
78  if (isActive()) {
79    if (!S.Stk.pop<bool>())
80      ActiveLabel = Label;
81  }
82  return true;
83}
84
85bool EvalEmitter::jump(const LabelTy &Label) {
86  if (isActive())
87    CurrentLabel = ActiveLabel = Label;
88  return true;
89}
90
91bool EvalEmitter::fallthrough(const LabelTy &Label) {
92  if (isActive())
93    ActiveLabel = Label;
94  CurrentLabel = Label;
95  return true;
96}
97
98template <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
105bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
106
107bool 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
196bool 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
206template <PrimType OpType>
207bool 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
220template <PrimType OpType>
221bool 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
234bool 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