Home | History | Annotate | Line # | Download | only in Interp
      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