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 const 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 Block *B = getLocal(I); 212 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 213 return true; 214 } 215 216 template <PrimType OpType> 217 bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { 218 if (!isActive()) 219 return true; 220 221 using T = typename PrimConv<OpType>::T; 222 223 Block *B = getLocal(I); 224 S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); 225 return true; 226 } 227 228 template <PrimType OpType> 229 bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) { 230 if (!isActive()) 231 return true; 232 233 using T = typename PrimConv<OpType>::T; 234 235 Block *B = getLocal(I); 236 *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>(); 237 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); 238 Desc.IsInitialized = true; 239 240 return true; 241 } 242 243 bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) { 244 if (!isActive()) 245 return true; 246 247 for (auto &Local : Descriptors[I]) { 248 Block *B = getLocal(Local.Offset); 249 S.deallocate(B); 250 } 251 252 return true; 253 } 254 255 //===----------------------------------------------------------------------===// 256 // Opcode evaluators 257 //===----------------------------------------------------------------------===// 258 259 #define GET_EVAL_IMPL 260 #include "Opcodes.inc" 261 #undef GET_EVAL_IMPL 262