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" 10*5f757f3fSDimitry Andric #include "ByteCodeGenError.h" 11a7dea167SDimitry Andric #include "Context.h" 1206c3fb27SDimitry Andric #include "Floating.h" 13a7dea167SDimitry Andric #include "Opcode.h" 14a7dea167SDimitry Andric #include "Program.h" 1506c3fb27SDimitry Andric #include "clang/AST/ASTLambda.h" 16a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h" 17*5f757f3fSDimitry Andric #include "clang/Basic/Builtins.h" 18349cc55cSDimitry Andric #include <type_traits> 19a7dea167SDimitry Andric 20a7dea167SDimitry Andric using namespace clang; 21a7dea167SDimitry Andric using namespace clang::interp; 22a7dea167SDimitry Andric 23bdd1243dSDimitry Andric Expected<Function *> 24bdd1243dSDimitry Andric ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { 25a7dea167SDimitry Andric // Set up argument indices. 26a7dea167SDimitry Andric unsigned ParamOffset = 0; 27a7dea167SDimitry Andric SmallVector<PrimType, 8> ParamTypes; 2806c3fb27SDimitry Andric SmallVector<unsigned, 8> ParamOffsets; 29a7dea167SDimitry Andric llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; 30a7dea167SDimitry Andric 31bdd1243dSDimitry Andric // If the return is not a primitive, a pointer to the storage where the 32bdd1243dSDimitry Andric // value is initialized in is passed as the first argument. See 'RVO' 33bdd1243dSDimitry Andric // elsewhere in the code. 34bdd1243dSDimitry Andric QualType Ty = FuncDecl->getReturnType(); 35bdd1243dSDimitry Andric bool HasRVO = false; 36a7dea167SDimitry Andric if (!Ty->isVoidType() && !Ctx.classify(Ty)) { 37bdd1243dSDimitry Andric HasRVO = true; 38bdd1243dSDimitry Andric ParamTypes.push_back(PT_Ptr); 3906c3fb27SDimitry Andric ParamOffsets.push_back(ParamOffset); 40bdd1243dSDimitry Andric ParamOffset += align(primSize(PT_Ptr)); 41bdd1243dSDimitry Andric } 42bdd1243dSDimitry Andric 43bdd1243dSDimitry Andric // If the function decl is a member decl, the next parameter is 44bdd1243dSDimitry Andric // the 'this' pointer. This parameter is pop()ed from the 45bdd1243dSDimitry Andric // InterpStack when calling the function. 46bdd1243dSDimitry Andric bool HasThisPointer = false; 4706c3fb27SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) { 48*5f757f3fSDimitry Andric if (MD->isImplicitObjectMemberFunction()) { 49bdd1243dSDimitry Andric HasThisPointer = true; 50a7dea167SDimitry Andric ParamTypes.push_back(PT_Ptr); 5106c3fb27SDimitry Andric ParamOffsets.push_back(ParamOffset); 52a7dea167SDimitry Andric ParamOffset += align(primSize(PT_Ptr)); 53a7dea167SDimitry Andric } 54a7dea167SDimitry Andric 5506c3fb27SDimitry Andric // Set up lambda capture to closure record field mapping. 5606c3fb27SDimitry Andric if (isLambdaCallOperator(MD)) { 5706c3fb27SDimitry Andric const Record *R = P.getOrCreateRecord(MD->getParent()); 5806c3fb27SDimitry Andric llvm::DenseMap<const ValueDecl *, FieldDecl *> LC; 5906c3fb27SDimitry Andric FieldDecl *LTC; 6006c3fb27SDimitry Andric 6106c3fb27SDimitry Andric MD->getParent()->getCaptureFields(LC, LTC); 6206c3fb27SDimitry Andric 6306c3fb27SDimitry Andric for (auto Cap : LC) { 64*5f757f3fSDimitry Andric // Static lambdas cannot have any captures. If this one does, 65*5f757f3fSDimitry Andric // it has already been diagnosed and we can only ignore it. 66*5f757f3fSDimitry Andric if (MD->isStatic()) 67*5f757f3fSDimitry Andric return nullptr; 68*5f757f3fSDimitry Andric 6906c3fb27SDimitry Andric unsigned Offset = R->getField(Cap.second)->Offset; 7006c3fb27SDimitry Andric this->LambdaCaptures[Cap.first] = { 7106c3fb27SDimitry Andric Offset, Cap.second->getType()->isReferenceType()}; 7206c3fb27SDimitry Andric } 73*5f757f3fSDimitry Andric if (LTC) 74*5f757f3fSDimitry Andric this->LambdaThisCapture = R->getField(LTC)->Offset; 7506c3fb27SDimitry Andric } 7606c3fb27SDimitry Andric } 7706c3fb27SDimitry Andric 78a7dea167SDimitry Andric // Assign descriptors to all parameters. 79a7dea167SDimitry Andric // Composite objects are lowered to pointers. 80bdd1243dSDimitry Andric for (const ParmVarDecl *PD : FuncDecl->parameters()) { 81*5f757f3fSDimitry Andric std::optional<PrimType> T = Ctx.classify(PD->getType()); 82*5f757f3fSDimitry Andric PrimType PT = T.value_or(PT_Ptr); 83*5f757f3fSDimitry Andric Descriptor *Desc = P.createDescriptor(PD, PT); 84*5f757f3fSDimitry Andric ParamDescriptors.insert({ParamOffset, {PT, Desc}}); 85*5f757f3fSDimitry Andric Params.insert({PD, {ParamOffset, T != std::nullopt}}); 8606c3fb27SDimitry Andric ParamOffsets.push_back(ParamOffset); 87*5f757f3fSDimitry Andric ParamOffset += align(primSize(PT)); 88*5f757f3fSDimitry Andric ParamTypes.push_back(PT); 89a7dea167SDimitry Andric } 90a7dea167SDimitry Andric 9106c3fb27SDimitry Andric // Create a handle over the emitted code. 9206c3fb27SDimitry Andric Function *Func = P.getFunction(FuncDecl); 93*5f757f3fSDimitry Andric if (!Func) { 94*5f757f3fSDimitry Andric bool IsUnevaluatedBuiltin = false; 95*5f757f3fSDimitry Andric if (unsigned BI = FuncDecl->getBuiltinID()) 96*5f757f3fSDimitry Andric IsUnevaluatedBuiltin = Ctx.getASTContext().BuiltinInfo.isUnevaluated(BI); 97*5f757f3fSDimitry Andric 98*5f757f3fSDimitry Andric Func = 99*5f757f3fSDimitry Andric P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), 100*5f757f3fSDimitry Andric std::move(ParamDescriptors), std::move(ParamOffsets), 101*5f757f3fSDimitry Andric HasThisPointer, HasRVO, IsUnevaluatedBuiltin); 102*5f757f3fSDimitry Andric } 103bdd1243dSDimitry Andric 104bdd1243dSDimitry Andric assert(Func); 10506c3fb27SDimitry Andric // For not-yet-defined functions, we only create a Function instance and 10606c3fb27SDimitry Andric // compile their body later. 107*5f757f3fSDimitry Andric if (!FuncDecl->isDefined()) { 108*5f757f3fSDimitry Andric Func->setDefined(false); 109bdd1243dSDimitry Andric return Func; 110*5f757f3fSDimitry Andric } 111*5f757f3fSDimitry Andric 112*5f757f3fSDimitry Andric Func->setDefined(true); 113*5f757f3fSDimitry Andric 114*5f757f3fSDimitry Andric // Lambda static invokers are a special case that we emit custom code for. 115*5f757f3fSDimitry Andric bool IsEligibleForCompilation = false; 116*5f757f3fSDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) 117*5f757f3fSDimitry Andric IsEligibleForCompilation = MD->isLambdaStaticInvoker(); 118*5f757f3fSDimitry Andric if (!IsEligibleForCompilation) 119*5f757f3fSDimitry Andric IsEligibleForCompilation = FuncDecl->isConstexpr(); 120bdd1243dSDimitry Andric 121a7dea167SDimitry Andric // Compile the function body. 122*5f757f3fSDimitry Andric if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) { 123a7dea167SDimitry Andric // Return a dummy function if compilation failed. 124a7dea167SDimitry Andric if (BailLocation) 125a7dea167SDimitry Andric return llvm::make_error<ByteCodeGenError>(*BailLocation); 126*5f757f3fSDimitry Andric 127bdd1243dSDimitry Andric Func->setIsFullyCompiled(true); 128a7dea167SDimitry Andric return Func; 129bdd1243dSDimitry Andric } 130*5f757f3fSDimitry Andric 131a7dea167SDimitry Andric // Create scopes from descriptors. 132a7dea167SDimitry Andric llvm::SmallVector<Scope, 2> Scopes; 133a7dea167SDimitry Andric for (auto &DS : Descriptors) { 134a7dea167SDimitry Andric Scopes.emplace_back(std::move(DS)); 135a7dea167SDimitry Andric } 136a7dea167SDimitry Andric 137a7dea167SDimitry Andric // Set the function's code. 138a7dea167SDimitry Andric Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap), 13906c3fb27SDimitry Andric std::move(Scopes), FuncDecl->hasBody()); 140bdd1243dSDimitry Andric Func->setIsFullyCompiled(true); 141a7dea167SDimitry Andric return Func; 142a7dea167SDimitry Andric } 143a7dea167SDimitry Andric 144a7dea167SDimitry Andric Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) { 145a7dea167SDimitry Andric NextLocalOffset += sizeof(Block); 146a7dea167SDimitry Andric unsigned Location = NextLocalOffset; 147a7dea167SDimitry Andric NextLocalOffset += align(D->getAllocSize()); 148a7dea167SDimitry Andric return {Location, D}; 149a7dea167SDimitry Andric } 150a7dea167SDimitry Andric 151a7dea167SDimitry Andric void ByteCodeEmitter::emitLabel(LabelTy Label) { 152a7dea167SDimitry Andric const size_t Target = Code.size(); 153a7dea167SDimitry Andric LabelOffsets.insert({Label, Target}); 15406c3fb27SDimitry Andric 15506c3fb27SDimitry Andric if (auto It = LabelRelocs.find(Label); 15606c3fb27SDimitry Andric It != LabelRelocs.end()) { 157a7dea167SDimitry Andric for (unsigned Reloc : It->second) { 158a7dea167SDimitry Andric using namespace llvm::support; 159a7dea167SDimitry Andric 16006c3fb27SDimitry Andric // Rewrite the operand of all jumps to this label. 161bdd1243dSDimitry Andric void *Location = Code.data() + Reloc - align(sizeof(int32_t)); 162bdd1243dSDimitry Andric assert(aligned(Location)); 163a7dea167SDimitry Andric const int32_t Offset = Target - static_cast<int64_t>(Reloc); 164*5f757f3fSDimitry Andric endian::write<int32_t, llvm::endianness::native>(Location, Offset); 165a7dea167SDimitry Andric } 166a7dea167SDimitry Andric LabelRelocs.erase(It); 167a7dea167SDimitry Andric } 168a7dea167SDimitry Andric } 169a7dea167SDimitry Andric 170a7dea167SDimitry Andric int32_t ByteCodeEmitter::getOffset(LabelTy Label) { 171a7dea167SDimitry Andric // Compute the PC offset which the jump is relative to. 172bdd1243dSDimitry Andric const int64_t Position = 173bdd1243dSDimitry Andric Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t)); 174bdd1243dSDimitry Andric assert(aligned(Position)); 175a7dea167SDimitry Andric 176a7dea167SDimitry Andric // If target is known, compute jump offset. 17706c3fb27SDimitry Andric if (auto It = LabelOffsets.find(Label); 17806c3fb27SDimitry Andric It != LabelOffsets.end()) 179a7dea167SDimitry Andric return It->second - Position; 180a7dea167SDimitry Andric 181a7dea167SDimitry Andric // Otherwise, record relocation and return dummy offset. 182a7dea167SDimitry Andric LabelRelocs[Label].push_back(Position); 183a7dea167SDimitry Andric return 0ull; 184a7dea167SDimitry Andric } 185a7dea167SDimitry Andric 186a7dea167SDimitry Andric bool ByteCodeEmitter::bail(const SourceLocation &Loc) { 187a7dea167SDimitry Andric if (!BailLocation) 188a7dea167SDimitry Andric BailLocation = Loc; 189a7dea167SDimitry Andric return false; 190a7dea167SDimitry Andric } 191a7dea167SDimitry Andric 192a7dea167SDimitry Andric /// Helper to write bytecode and bail out if 32-bit offsets become invalid. 193349cc55cSDimitry Andric /// Pointers will be automatically marshalled as 32-bit IDs. 194349cc55cSDimitry Andric template <typename T> 19506c3fb27SDimitry Andric static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, 196bdd1243dSDimitry Andric bool &Success) { 197bdd1243dSDimitry Andric size_t Size; 198bdd1243dSDimitry Andric 199bdd1243dSDimitry Andric if constexpr (std::is_pointer_v<T>) 200bdd1243dSDimitry Andric Size = sizeof(uint32_t); 201bdd1243dSDimitry Andric else 202bdd1243dSDimitry Andric Size = sizeof(T); 203bdd1243dSDimitry Andric 204a7dea167SDimitry Andric if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 205a7dea167SDimitry Andric Success = false; 206a7dea167SDimitry Andric return; 207a7dea167SDimitry Andric } 208349cc55cSDimitry Andric 209bdd1243dSDimitry Andric // Access must be aligned! 210bdd1243dSDimitry Andric size_t ValPos = align(Code.size()); 211bdd1243dSDimitry Andric Size = align(Size); 212bdd1243dSDimitry Andric assert(aligned(ValPos + Size)); 213bdd1243dSDimitry Andric Code.resize(ValPos + Size); 214349cc55cSDimitry Andric 215bdd1243dSDimitry Andric if constexpr (!std::is_pointer_v<T>) { 216bdd1243dSDimitry Andric new (Code.data() + ValPos) T(Val); 217bdd1243dSDimitry Andric } else { 218349cc55cSDimitry Andric uint32_t ID = P.getOrCreateNativePointer(Val); 219bdd1243dSDimitry Andric new (Code.data() + ValPos) uint32_t(ID); 220bdd1243dSDimitry Andric } 221349cc55cSDimitry Andric } 222349cc55cSDimitry Andric 223*5f757f3fSDimitry Andric template <> 224*5f757f3fSDimitry Andric void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val, 225*5f757f3fSDimitry Andric bool &Success) { 226*5f757f3fSDimitry Andric size_t Size = Val.bytesToSerialize(); 227*5f757f3fSDimitry Andric 228*5f757f3fSDimitry Andric if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 229*5f757f3fSDimitry Andric Success = false; 230*5f757f3fSDimitry Andric return; 231*5f757f3fSDimitry Andric } 232*5f757f3fSDimitry Andric 233*5f757f3fSDimitry Andric // Access must be aligned! 234*5f757f3fSDimitry Andric size_t ValPos = align(Code.size()); 235*5f757f3fSDimitry Andric Size = align(Size); 236*5f757f3fSDimitry Andric assert(aligned(ValPos + Size)); 237*5f757f3fSDimitry Andric Code.resize(ValPos + Size); 238*5f757f3fSDimitry Andric 239*5f757f3fSDimitry Andric Val.serialize(Code.data() + ValPos); 240*5f757f3fSDimitry Andric } 241*5f757f3fSDimitry Andric 242349cc55cSDimitry Andric template <typename... Tys> 243349cc55cSDimitry Andric bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { 244349cc55cSDimitry Andric bool Success = true; 245a7dea167SDimitry Andric 24606c3fb27SDimitry Andric // The opcode is followed by arguments. The source info is 24706c3fb27SDimitry Andric // attached to the address after the opcode. 248349cc55cSDimitry Andric emit(P, Code, Op, Success); 249a7dea167SDimitry Andric if (SI) 250a7dea167SDimitry Andric SrcMap.emplace_back(Code.size(), SI); 251a7dea167SDimitry Andric 25206c3fb27SDimitry Andric // The initializer list forces the expression to be evaluated 25306c3fb27SDimitry Andric // for each argument in the variadic template, in order. 254349cc55cSDimitry Andric (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...}; 255a7dea167SDimitry Andric 256a7dea167SDimitry Andric return Success; 257a7dea167SDimitry Andric } 258a7dea167SDimitry Andric 259a7dea167SDimitry Andric bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) { 260a7dea167SDimitry Andric return emitJt(getOffset(Label), SourceInfo{}); 261a7dea167SDimitry Andric } 262a7dea167SDimitry Andric 263a7dea167SDimitry Andric bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) { 264a7dea167SDimitry Andric return emitJf(getOffset(Label), SourceInfo{}); 265a7dea167SDimitry Andric } 266a7dea167SDimitry Andric 267a7dea167SDimitry Andric bool ByteCodeEmitter::jump(const LabelTy &Label) { 268a7dea167SDimitry Andric return emitJmp(getOffset(Label), SourceInfo{}); 269a7dea167SDimitry Andric } 270a7dea167SDimitry Andric 271a7dea167SDimitry Andric bool ByteCodeEmitter::fallthrough(const LabelTy &Label) { 272a7dea167SDimitry Andric emitLabel(Label); 273a7dea167SDimitry Andric return true; 274a7dea167SDimitry Andric } 275a7dea167SDimitry Andric 276a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 277a7dea167SDimitry Andric // Opcode emitters 278a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 279a7dea167SDimitry Andric 280a7dea167SDimitry Andric #define GET_LINK_IMPL 281a7dea167SDimitry Andric #include "Opcodes.inc" 282a7dea167SDimitry Andric #undef GET_LINK_IMPL 283