1 //===--- ByteCodeEmitter.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 "ByteCodeEmitter.h" 10 #include "Context.h" 11 #include "Floating.h" 12 #include "Opcode.h" 13 #include "Program.h" 14 #include "clang/AST/ASTLambda.h" 15 #include "clang/AST/DeclCXX.h" 16 #include <type_traits> 17 18 using namespace clang; 19 using namespace clang::interp; 20 21 using APSInt = llvm::APSInt; 22 using Error = llvm::Error; 23 24 Expected<Function *> 25 ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { 26 // Set up argument indices. 27 unsigned ParamOffset = 0; 28 SmallVector<PrimType, 8> ParamTypes; 29 SmallVector<unsigned, 8> ParamOffsets; 30 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; 31 32 // If the return is not a primitive, a pointer to the storage where the 33 // value is initialized in is passed as the first argument. See 'RVO' 34 // elsewhere in the code. 35 QualType Ty = FuncDecl->getReturnType(); 36 bool HasRVO = false; 37 if (!Ty->isVoidType() && !Ctx.classify(Ty)) { 38 HasRVO = true; 39 ParamTypes.push_back(PT_Ptr); 40 ParamOffsets.push_back(ParamOffset); 41 ParamOffset += align(primSize(PT_Ptr)); 42 } 43 44 // If the function decl is a member decl, the next parameter is 45 // the 'this' pointer. This parameter is pop()ed from the 46 // InterpStack when calling the function. 47 bool HasThisPointer = false; 48 if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) { 49 if (MD->isInstance()) { 50 HasThisPointer = true; 51 ParamTypes.push_back(PT_Ptr); 52 ParamOffsets.push_back(ParamOffset); 53 ParamOffset += align(primSize(PT_Ptr)); 54 } 55 56 // Set up lambda capture to closure record field mapping. 57 if (isLambdaCallOperator(MD)) { 58 const Record *R = P.getOrCreateRecord(MD->getParent()); 59 llvm::DenseMap<const ValueDecl *, FieldDecl *> LC; 60 FieldDecl *LTC; 61 62 MD->getParent()->getCaptureFields(LC, LTC); 63 64 for (auto Cap : LC) { 65 unsigned Offset = R->getField(Cap.second)->Offset; 66 this->LambdaCaptures[Cap.first] = { 67 Offset, Cap.second->getType()->isReferenceType()}; 68 } 69 // FIXME: LambdaThisCapture 70 (void)LTC; 71 } 72 } 73 74 // Assign descriptors to all parameters. 75 // Composite objects are lowered to pointers. 76 for (const ParmVarDecl *PD : FuncDecl->parameters()) { 77 PrimType Ty = Ctx.classify(PD->getType()).value_or(PT_Ptr); 78 Descriptor *Desc = P.createDescriptor(PD, Ty); 79 ParamDescriptors.insert({ParamOffset, {Ty, Desc}}); 80 Params.insert({PD, ParamOffset}); 81 ParamOffsets.push_back(ParamOffset); 82 ParamOffset += align(primSize(Ty)); 83 ParamTypes.push_back(Ty); 84 } 85 86 // Create a handle over the emitted code. 87 Function *Func = P.getFunction(FuncDecl); 88 if (!Func) 89 Func = P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), 90 std::move(ParamDescriptors), 91 std::move(ParamOffsets), HasThisPointer, HasRVO); 92 93 assert(Func); 94 // For not-yet-defined functions, we only create a Function instance and 95 // compile their body later. 96 if (!FuncDecl->isDefined()) 97 return Func; 98 99 // Compile the function body. 100 if (!FuncDecl->isConstexpr() || !visitFunc(FuncDecl)) { 101 // Return a dummy function if compilation failed. 102 if (BailLocation) 103 return llvm::make_error<ByteCodeGenError>(*BailLocation); 104 else { 105 Func->setIsFullyCompiled(true); 106 return Func; 107 } 108 } else { 109 // Create scopes from descriptors. 110 llvm::SmallVector<Scope, 2> Scopes; 111 for (auto &DS : Descriptors) { 112 Scopes.emplace_back(std::move(DS)); 113 } 114 115 // Set the function's code. 116 Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap), 117 std::move(Scopes), FuncDecl->hasBody()); 118 Func->setIsFullyCompiled(true); 119 return Func; 120 } 121 } 122 123 Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) { 124 NextLocalOffset += sizeof(Block); 125 unsigned Location = NextLocalOffset; 126 NextLocalOffset += align(D->getAllocSize()); 127 return {Location, D}; 128 } 129 130 void ByteCodeEmitter::emitLabel(LabelTy Label) { 131 const size_t Target = Code.size(); 132 LabelOffsets.insert({Label, Target}); 133 134 if (auto It = LabelRelocs.find(Label); 135 It != LabelRelocs.end()) { 136 for (unsigned Reloc : It->second) { 137 using namespace llvm::support; 138 139 // Rewrite the operand of all jumps to this label. 140 void *Location = Code.data() + Reloc - align(sizeof(int32_t)); 141 assert(aligned(Location)); 142 const int32_t Offset = Target - static_cast<int64_t>(Reloc); 143 endian::write<int32_t, endianness::native, 1>(Location, Offset); 144 } 145 LabelRelocs.erase(It); 146 } 147 } 148 149 int32_t ByteCodeEmitter::getOffset(LabelTy Label) { 150 // Compute the PC offset which the jump is relative to. 151 const int64_t Position = 152 Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t)); 153 assert(aligned(Position)); 154 155 // If target is known, compute jump offset. 156 if (auto It = LabelOffsets.find(Label); 157 It != LabelOffsets.end()) 158 return It->second - Position; 159 160 // Otherwise, record relocation and return dummy offset. 161 LabelRelocs[Label].push_back(Position); 162 return 0ull; 163 } 164 165 bool ByteCodeEmitter::bail(const SourceLocation &Loc) { 166 if (!BailLocation) 167 BailLocation = Loc; 168 return false; 169 } 170 171 /// Helper to write bytecode and bail out if 32-bit offsets become invalid. 172 /// Pointers will be automatically marshalled as 32-bit IDs. 173 template <typename T> 174 static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, 175 bool &Success) { 176 size_t Size; 177 178 if constexpr (std::is_pointer_v<T>) 179 Size = sizeof(uint32_t); 180 else 181 Size = sizeof(T); 182 183 if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 184 Success = false; 185 return; 186 } 187 188 // Access must be aligned! 189 size_t ValPos = align(Code.size()); 190 Size = align(Size); 191 assert(aligned(ValPos + Size)); 192 Code.resize(ValPos + Size); 193 194 if constexpr (!std::is_pointer_v<T>) { 195 new (Code.data() + ValPos) T(Val); 196 } else { 197 uint32_t ID = P.getOrCreateNativePointer(Val); 198 new (Code.data() + ValPos) uint32_t(ID); 199 } 200 } 201 202 template <typename... Tys> 203 bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { 204 bool Success = true; 205 206 // The opcode is followed by arguments. The source info is 207 // attached to the address after the opcode. 208 emit(P, Code, Op, Success); 209 if (SI) 210 SrcMap.emplace_back(Code.size(), SI); 211 212 // The initializer list forces the expression to be evaluated 213 // for each argument in the variadic template, in order. 214 (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...}; 215 216 return Success; 217 } 218 219 bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) { 220 return emitJt(getOffset(Label), SourceInfo{}); 221 } 222 223 bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) { 224 return emitJf(getOffset(Label), SourceInfo{}); 225 } 226 227 bool ByteCodeEmitter::jump(const LabelTy &Label) { 228 return emitJmp(getOffset(Label), SourceInfo{}); 229 } 230 231 bool ByteCodeEmitter::fallthrough(const LabelTy &Label) { 232 emitLabel(Label); 233 return true; 234 } 235 236 //===----------------------------------------------------------------------===// 237 // Opcode emitters 238 //===----------------------------------------------------------------------===// 239 240 #define GET_LINK_IMPL 241 #include "Opcodes.inc" 242 #undef GET_LINK_IMPL 243