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