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