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" 105f757f3fSDimitry 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" 175f757f3fSDimitry 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 23*7a6dacacSDimitry Andric Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { 24a7dea167SDimitry Andric // Set up argument indices. 25a7dea167SDimitry Andric unsigned ParamOffset = 0; 26a7dea167SDimitry Andric SmallVector<PrimType, 8> ParamTypes; 2706c3fb27SDimitry Andric SmallVector<unsigned, 8> ParamOffsets; 28a7dea167SDimitry Andric llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; 29a7dea167SDimitry Andric 30bdd1243dSDimitry Andric // If the return is not a primitive, a pointer to the storage where the 31bdd1243dSDimitry Andric // value is initialized in is passed as the first argument. See 'RVO' 32bdd1243dSDimitry Andric // elsewhere in the code. 33bdd1243dSDimitry Andric QualType Ty = FuncDecl->getReturnType(); 34bdd1243dSDimitry Andric bool HasRVO = false; 35a7dea167SDimitry Andric if (!Ty->isVoidType() && !Ctx.classify(Ty)) { 36bdd1243dSDimitry Andric HasRVO = true; 37bdd1243dSDimitry Andric ParamTypes.push_back(PT_Ptr); 3806c3fb27SDimitry Andric ParamOffsets.push_back(ParamOffset); 39bdd1243dSDimitry Andric ParamOffset += align(primSize(PT_Ptr)); 40bdd1243dSDimitry Andric } 41bdd1243dSDimitry Andric 42bdd1243dSDimitry Andric // If the function decl is a member decl, the next parameter is 43bdd1243dSDimitry Andric // the 'this' pointer. This parameter is pop()ed from the 44bdd1243dSDimitry Andric // InterpStack when calling the function. 45bdd1243dSDimitry Andric bool HasThisPointer = false; 4606c3fb27SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) { 475f757f3fSDimitry Andric if (MD->isImplicitObjectMemberFunction()) { 48bdd1243dSDimitry Andric HasThisPointer = true; 49a7dea167SDimitry Andric ParamTypes.push_back(PT_Ptr); 5006c3fb27SDimitry Andric ParamOffsets.push_back(ParamOffset); 51a7dea167SDimitry Andric ParamOffset += align(primSize(PT_Ptr)); 52a7dea167SDimitry Andric } 53a7dea167SDimitry Andric 5406c3fb27SDimitry Andric // Set up lambda capture to closure record field mapping. 5506c3fb27SDimitry Andric if (isLambdaCallOperator(MD)) { 5606c3fb27SDimitry Andric const Record *R = P.getOrCreateRecord(MD->getParent()); 5706c3fb27SDimitry Andric llvm::DenseMap<const ValueDecl *, FieldDecl *> LC; 5806c3fb27SDimitry Andric FieldDecl *LTC; 5906c3fb27SDimitry Andric 6006c3fb27SDimitry Andric MD->getParent()->getCaptureFields(LC, LTC); 6106c3fb27SDimitry Andric 6206c3fb27SDimitry Andric for (auto Cap : LC) { 635f757f3fSDimitry Andric // Static lambdas cannot have any captures. If this one does, 645f757f3fSDimitry Andric // it has already been diagnosed and we can only ignore it. 655f757f3fSDimitry Andric if (MD->isStatic()) 665f757f3fSDimitry Andric return nullptr; 675f757f3fSDimitry Andric 6806c3fb27SDimitry Andric unsigned Offset = R->getField(Cap.second)->Offset; 6906c3fb27SDimitry Andric this->LambdaCaptures[Cap.first] = { 7006c3fb27SDimitry Andric Offset, Cap.second->getType()->isReferenceType()}; 7106c3fb27SDimitry Andric } 725f757f3fSDimitry Andric if (LTC) 735f757f3fSDimitry Andric this->LambdaThisCapture = R->getField(LTC)->Offset; 7406c3fb27SDimitry Andric } 7506c3fb27SDimitry Andric } 7606c3fb27SDimitry Andric 77a7dea167SDimitry Andric // Assign descriptors to all parameters. 78a7dea167SDimitry Andric // Composite objects are lowered to pointers. 79bdd1243dSDimitry Andric for (const ParmVarDecl *PD : FuncDecl->parameters()) { 805f757f3fSDimitry Andric std::optional<PrimType> T = Ctx.classify(PD->getType()); 815f757f3fSDimitry Andric PrimType PT = T.value_or(PT_Ptr); 825f757f3fSDimitry Andric Descriptor *Desc = P.createDescriptor(PD, PT); 835f757f3fSDimitry Andric ParamDescriptors.insert({ParamOffset, {PT, Desc}}); 845f757f3fSDimitry Andric Params.insert({PD, {ParamOffset, T != std::nullopt}}); 8506c3fb27SDimitry Andric ParamOffsets.push_back(ParamOffset); 865f757f3fSDimitry Andric ParamOffset += align(primSize(PT)); 875f757f3fSDimitry Andric ParamTypes.push_back(PT); 88a7dea167SDimitry Andric } 89a7dea167SDimitry Andric 9006c3fb27SDimitry Andric // Create a handle over the emitted code. 9106c3fb27SDimitry Andric Function *Func = P.getFunction(FuncDecl); 925f757f3fSDimitry Andric if (!Func) { 935f757f3fSDimitry Andric bool IsUnevaluatedBuiltin = false; 945f757f3fSDimitry Andric if (unsigned BI = FuncDecl->getBuiltinID()) 955f757f3fSDimitry Andric IsUnevaluatedBuiltin = Ctx.getASTContext().BuiltinInfo.isUnevaluated(BI); 965f757f3fSDimitry Andric 975f757f3fSDimitry Andric Func = 985f757f3fSDimitry Andric P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), 995f757f3fSDimitry Andric std::move(ParamDescriptors), std::move(ParamOffsets), 1005f757f3fSDimitry Andric HasThisPointer, HasRVO, IsUnevaluatedBuiltin); 1015f757f3fSDimitry Andric } 102bdd1243dSDimitry Andric 103bdd1243dSDimitry Andric assert(Func); 10406c3fb27SDimitry Andric // For not-yet-defined functions, we only create a Function instance and 10506c3fb27SDimitry Andric // compile their body later. 1065f757f3fSDimitry Andric if (!FuncDecl->isDefined()) { 1075f757f3fSDimitry Andric Func->setDefined(false); 108bdd1243dSDimitry Andric return Func; 1095f757f3fSDimitry Andric } 1105f757f3fSDimitry Andric 1115f757f3fSDimitry Andric Func->setDefined(true); 1125f757f3fSDimitry Andric 1135f757f3fSDimitry Andric // Lambda static invokers are a special case that we emit custom code for. 1145f757f3fSDimitry Andric bool IsEligibleForCompilation = false; 1155f757f3fSDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) 1165f757f3fSDimitry Andric IsEligibleForCompilation = MD->isLambdaStaticInvoker(); 1175f757f3fSDimitry Andric if (!IsEligibleForCompilation) 1185f757f3fSDimitry Andric IsEligibleForCompilation = FuncDecl->isConstexpr(); 119bdd1243dSDimitry Andric 120a7dea167SDimitry Andric // Compile the function body. 1215f757f3fSDimitry Andric if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) { 122bdd1243dSDimitry Andric Func->setIsFullyCompiled(true); 123a7dea167SDimitry Andric return Func; 124bdd1243dSDimitry Andric } 1255f757f3fSDimitry Andric 126a7dea167SDimitry Andric // Create scopes from descriptors. 127a7dea167SDimitry Andric llvm::SmallVector<Scope, 2> Scopes; 128a7dea167SDimitry Andric for (auto &DS : Descriptors) { 129a7dea167SDimitry Andric Scopes.emplace_back(std::move(DS)); 130a7dea167SDimitry Andric } 131a7dea167SDimitry Andric 132a7dea167SDimitry Andric // Set the function's code. 133a7dea167SDimitry Andric Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap), 13406c3fb27SDimitry Andric std::move(Scopes), FuncDecl->hasBody()); 135bdd1243dSDimitry Andric Func->setIsFullyCompiled(true); 136a7dea167SDimitry Andric return Func; 137a7dea167SDimitry Andric } 138a7dea167SDimitry Andric 139a7dea167SDimitry Andric Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) { 140a7dea167SDimitry Andric NextLocalOffset += sizeof(Block); 141a7dea167SDimitry Andric unsigned Location = NextLocalOffset; 142a7dea167SDimitry Andric NextLocalOffset += align(D->getAllocSize()); 143a7dea167SDimitry Andric return {Location, D}; 144a7dea167SDimitry Andric } 145a7dea167SDimitry Andric 146a7dea167SDimitry Andric void ByteCodeEmitter::emitLabel(LabelTy Label) { 147a7dea167SDimitry Andric const size_t Target = Code.size(); 148a7dea167SDimitry Andric LabelOffsets.insert({Label, Target}); 14906c3fb27SDimitry Andric 15006c3fb27SDimitry Andric if (auto It = LabelRelocs.find(Label); 15106c3fb27SDimitry Andric It != LabelRelocs.end()) { 152a7dea167SDimitry Andric for (unsigned Reloc : It->second) { 153a7dea167SDimitry Andric using namespace llvm::support; 154a7dea167SDimitry Andric 15506c3fb27SDimitry Andric // Rewrite the operand of all jumps to this label. 156bdd1243dSDimitry Andric void *Location = Code.data() + Reloc - align(sizeof(int32_t)); 157bdd1243dSDimitry Andric assert(aligned(Location)); 158a7dea167SDimitry Andric const int32_t Offset = Target - static_cast<int64_t>(Reloc); 1595f757f3fSDimitry Andric endian::write<int32_t, llvm::endianness::native>(Location, Offset); 160a7dea167SDimitry Andric } 161a7dea167SDimitry Andric LabelRelocs.erase(It); 162a7dea167SDimitry Andric } 163a7dea167SDimitry Andric } 164a7dea167SDimitry Andric 165a7dea167SDimitry Andric int32_t ByteCodeEmitter::getOffset(LabelTy Label) { 166a7dea167SDimitry Andric // Compute the PC offset which the jump is relative to. 167bdd1243dSDimitry Andric const int64_t Position = 168bdd1243dSDimitry Andric Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t)); 169bdd1243dSDimitry Andric assert(aligned(Position)); 170a7dea167SDimitry Andric 171a7dea167SDimitry Andric // If target is known, compute jump offset. 17206c3fb27SDimitry Andric if (auto It = LabelOffsets.find(Label); 17306c3fb27SDimitry Andric It != LabelOffsets.end()) 174a7dea167SDimitry Andric return It->second - Position; 175a7dea167SDimitry Andric 176a7dea167SDimitry Andric // Otherwise, record relocation and return dummy offset. 177a7dea167SDimitry Andric LabelRelocs[Label].push_back(Position); 178a7dea167SDimitry Andric return 0ull; 179a7dea167SDimitry Andric } 180a7dea167SDimitry Andric 181a7dea167SDimitry Andric /// Helper to write bytecode and bail out if 32-bit offsets become invalid. 182349cc55cSDimitry Andric /// Pointers will be automatically marshalled as 32-bit IDs. 183349cc55cSDimitry Andric template <typename T> 18406c3fb27SDimitry Andric static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, 185bdd1243dSDimitry Andric bool &Success) { 186bdd1243dSDimitry Andric size_t Size; 187bdd1243dSDimitry Andric 188bdd1243dSDimitry Andric if constexpr (std::is_pointer_v<T>) 189bdd1243dSDimitry Andric Size = sizeof(uint32_t); 190bdd1243dSDimitry Andric else 191bdd1243dSDimitry Andric Size = sizeof(T); 192bdd1243dSDimitry Andric 193a7dea167SDimitry Andric if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 194a7dea167SDimitry Andric Success = false; 195a7dea167SDimitry Andric return; 196a7dea167SDimitry Andric } 197349cc55cSDimitry Andric 198bdd1243dSDimitry Andric // Access must be aligned! 199bdd1243dSDimitry Andric size_t ValPos = align(Code.size()); 200bdd1243dSDimitry Andric Size = align(Size); 201bdd1243dSDimitry Andric assert(aligned(ValPos + Size)); 202bdd1243dSDimitry Andric Code.resize(ValPos + Size); 203349cc55cSDimitry Andric 204bdd1243dSDimitry Andric if constexpr (!std::is_pointer_v<T>) { 205bdd1243dSDimitry Andric new (Code.data() + ValPos) T(Val); 206bdd1243dSDimitry Andric } else { 207349cc55cSDimitry Andric uint32_t ID = P.getOrCreateNativePointer(Val); 208bdd1243dSDimitry Andric new (Code.data() + ValPos) uint32_t(ID); 209bdd1243dSDimitry Andric } 210349cc55cSDimitry Andric } 211349cc55cSDimitry Andric 2125f757f3fSDimitry Andric template <> 2135f757f3fSDimitry Andric void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val, 2145f757f3fSDimitry Andric bool &Success) { 2155f757f3fSDimitry Andric size_t Size = Val.bytesToSerialize(); 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 2185f757f3fSDimitry Andric Success = false; 2195f757f3fSDimitry Andric return; 2205f757f3fSDimitry Andric } 2215f757f3fSDimitry Andric 2225f757f3fSDimitry Andric // Access must be aligned! 2235f757f3fSDimitry Andric size_t ValPos = align(Code.size()); 2245f757f3fSDimitry Andric Size = align(Size); 2255f757f3fSDimitry Andric assert(aligned(ValPos + Size)); 2265f757f3fSDimitry Andric Code.resize(ValPos + Size); 2275f757f3fSDimitry Andric 2285f757f3fSDimitry Andric Val.serialize(Code.data() + ValPos); 2295f757f3fSDimitry Andric } 2305f757f3fSDimitry Andric 231349cc55cSDimitry Andric template <typename... Tys> 232349cc55cSDimitry Andric bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { 233349cc55cSDimitry Andric bool Success = true; 234a7dea167SDimitry Andric 23506c3fb27SDimitry Andric // The opcode is followed by arguments. The source info is 23606c3fb27SDimitry Andric // attached to the address after the opcode. 237349cc55cSDimitry Andric emit(P, Code, Op, Success); 238a7dea167SDimitry Andric if (SI) 239a7dea167SDimitry Andric SrcMap.emplace_back(Code.size(), SI); 240a7dea167SDimitry Andric 24106c3fb27SDimitry Andric // The initializer list forces the expression to be evaluated 24206c3fb27SDimitry Andric // for each argument in the variadic template, in order. 243349cc55cSDimitry Andric (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...}; 244a7dea167SDimitry Andric 245a7dea167SDimitry Andric return Success; 246a7dea167SDimitry Andric } 247a7dea167SDimitry Andric 248a7dea167SDimitry Andric bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) { 249a7dea167SDimitry Andric return emitJt(getOffset(Label), SourceInfo{}); 250a7dea167SDimitry Andric } 251a7dea167SDimitry Andric 252a7dea167SDimitry Andric bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) { 253a7dea167SDimitry Andric return emitJf(getOffset(Label), SourceInfo{}); 254a7dea167SDimitry Andric } 255a7dea167SDimitry Andric 256a7dea167SDimitry Andric bool ByteCodeEmitter::jump(const LabelTy &Label) { 257a7dea167SDimitry Andric return emitJmp(getOffset(Label), SourceInfo{}); 258a7dea167SDimitry Andric } 259a7dea167SDimitry Andric 260a7dea167SDimitry Andric bool ByteCodeEmitter::fallthrough(const LabelTy &Label) { 261a7dea167SDimitry Andric emitLabel(Label); 262a7dea167SDimitry Andric return true; 263a7dea167SDimitry Andric } 264a7dea167SDimitry Andric 265a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 266a7dea167SDimitry Andric // Opcode emitters 267a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 268a7dea167SDimitry Andric 269a7dea167SDimitry Andric #define GET_LINK_IMPL 270a7dea167SDimitry Andric #include "Opcodes.inc" 271a7dea167SDimitry Andric #undef GET_LINK_IMPL 272