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