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