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" 14*349cc55cSDimitry 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 22a7dea167SDimitry Andric Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) { 23a7dea167SDimitry Andric // Do not try to compile undefined functions. 24a7dea167SDimitry Andric if (!F->isDefined(F) || (!F->hasBody() && F->willHaveBody())) 25a7dea167SDimitry Andric return nullptr; 26a7dea167SDimitry Andric 27a7dea167SDimitry Andric // Set up argument indices. 28a7dea167SDimitry Andric unsigned ParamOffset = 0; 29a7dea167SDimitry Andric SmallVector<PrimType, 8> ParamTypes; 30a7dea167SDimitry Andric llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; 31a7dea167SDimitry Andric 32a7dea167SDimitry Andric // If the return is not a primitive, a pointer to the storage where the value 33a7dea167SDimitry Andric // is initialized in is passed as the first argument. 34a7dea167SDimitry Andric QualType Ty = F->getReturnType(); 35a7dea167SDimitry Andric if (!Ty->isVoidType() && !Ctx.classify(Ty)) { 36a7dea167SDimitry Andric ParamTypes.push_back(PT_Ptr); 37a7dea167SDimitry Andric ParamOffset += align(primSize(PT_Ptr)); 38a7dea167SDimitry Andric } 39a7dea167SDimitry Andric 40a7dea167SDimitry Andric // Assign descriptors to all parameters. 41a7dea167SDimitry Andric // Composite objects are lowered to pointers. 42a7dea167SDimitry Andric for (const ParmVarDecl *PD : F->parameters()) { 43a7dea167SDimitry Andric PrimType Ty; 44a7dea167SDimitry Andric if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) { 45a7dea167SDimitry Andric Ty = *T; 46a7dea167SDimitry Andric } else { 47a7dea167SDimitry Andric Ty = PT_Ptr; 48a7dea167SDimitry Andric } 49a7dea167SDimitry Andric 50a7dea167SDimitry Andric Descriptor *Desc = P.createDescriptor(PD, Ty); 51a7dea167SDimitry Andric ParamDescriptors.insert({ParamOffset, {Ty, Desc}}); 52a7dea167SDimitry Andric Params.insert({PD, ParamOffset}); 53a7dea167SDimitry Andric ParamOffset += align(primSize(Ty)); 54a7dea167SDimitry Andric ParamTypes.push_back(Ty); 55a7dea167SDimitry Andric } 56a7dea167SDimitry Andric 57a7dea167SDimitry Andric // Create a handle over the emitted code. 58a7dea167SDimitry Andric Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes), 59a7dea167SDimitry Andric std::move(ParamDescriptors)); 60a7dea167SDimitry Andric // Compile the function body. 61a7dea167SDimitry Andric if (!F->isConstexpr() || !visitFunc(F)) { 62a7dea167SDimitry Andric // Return a dummy function if compilation failed. 63a7dea167SDimitry Andric if (BailLocation) 64a7dea167SDimitry Andric return llvm::make_error<ByteCodeGenError>(*BailLocation); 65a7dea167SDimitry Andric else 66a7dea167SDimitry Andric return Func; 67a7dea167SDimitry Andric } else { 68a7dea167SDimitry Andric // Create scopes from descriptors. 69a7dea167SDimitry Andric llvm::SmallVector<Scope, 2> Scopes; 70a7dea167SDimitry Andric for (auto &DS : Descriptors) { 71a7dea167SDimitry Andric Scopes.emplace_back(std::move(DS)); 72a7dea167SDimitry Andric } 73a7dea167SDimitry Andric 74a7dea167SDimitry Andric // Set the function's code. 75a7dea167SDimitry Andric Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap), 76a7dea167SDimitry Andric std::move(Scopes)); 77a7dea167SDimitry Andric return Func; 78a7dea167SDimitry Andric } 79a7dea167SDimitry Andric } 80a7dea167SDimitry Andric 81a7dea167SDimitry Andric Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) { 82a7dea167SDimitry Andric NextLocalOffset += sizeof(Block); 83a7dea167SDimitry Andric unsigned Location = NextLocalOffset; 84a7dea167SDimitry Andric NextLocalOffset += align(D->getAllocSize()); 85a7dea167SDimitry Andric return {Location, D}; 86a7dea167SDimitry Andric } 87a7dea167SDimitry Andric 88a7dea167SDimitry Andric void ByteCodeEmitter::emitLabel(LabelTy Label) { 89a7dea167SDimitry Andric const size_t Target = Code.size(); 90a7dea167SDimitry Andric LabelOffsets.insert({Label, Target}); 91a7dea167SDimitry Andric auto It = LabelRelocs.find(Label); 92a7dea167SDimitry Andric if (It != LabelRelocs.end()) { 93a7dea167SDimitry Andric for (unsigned Reloc : It->second) { 94a7dea167SDimitry Andric using namespace llvm::support; 95a7dea167SDimitry Andric 96a7dea167SDimitry Andric /// Rewrite the operand of all jumps to this label. 97a7dea167SDimitry Andric void *Location = Code.data() + Reloc - sizeof(int32_t); 98a7dea167SDimitry Andric const int32_t Offset = Target - static_cast<int64_t>(Reloc); 99a7dea167SDimitry Andric endian::write<int32_t, endianness::native, 1>(Location, Offset); 100a7dea167SDimitry Andric } 101a7dea167SDimitry Andric LabelRelocs.erase(It); 102a7dea167SDimitry Andric } 103a7dea167SDimitry Andric } 104a7dea167SDimitry Andric 105a7dea167SDimitry Andric int32_t ByteCodeEmitter::getOffset(LabelTy Label) { 106a7dea167SDimitry Andric // Compute the PC offset which the jump is relative to. 107a7dea167SDimitry Andric const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t); 108a7dea167SDimitry Andric 109a7dea167SDimitry Andric // If target is known, compute jump offset. 110a7dea167SDimitry Andric auto It = LabelOffsets.find(Label); 111a7dea167SDimitry Andric if (It != LabelOffsets.end()) { 112a7dea167SDimitry Andric return It->second - Position; 113a7dea167SDimitry Andric } 114a7dea167SDimitry Andric 115a7dea167SDimitry Andric // Otherwise, record relocation and return dummy offset. 116a7dea167SDimitry Andric LabelRelocs[Label].push_back(Position); 117a7dea167SDimitry Andric return 0ull; 118a7dea167SDimitry Andric } 119a7dea167SDimitry Andric 120a7dea167SDimitry Andric bool ByteCodeEmitter::bail(const SourceLocation &Loc) { 121a7dea167SDimitry Andric if (!BailLocation) 122a7dea167SDimitry Andric BailLocation = Loc; 123a7dea167SDimitry Andric return false; 124a7dea167SDimitry Andric } 125a7dea167SDimitry Andric 126a7dea167SDimitry Andric /// Helper to write bytecode and bail out if 32-bit offsets become invalid. 127*349cc55cSDimitry Andric /// Pointers will be automatically marshalled as 32-bit IDs. 128*349cc55cSDimitry Andric template <typename T> 129*349cc55cSDimitry Andric static std::enable_if_t<!std::is_pointer<T>::value, void> 130*349cc55cSDimitry Andric emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) { 131*349cc55cSDimitry Andric size_t Size = sizeof(Val); 132a7dea167SDimitry Andric if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 133a7dea167SDimitry Andric Success = false; 134a7dea167SDimitry Andric return; 135a7dea167SDimitry Andric } 136*349cc55cSDimitry Andric 137*349cc55cSDimitry Andric const char *Data = reinterpret_cast<const char *>(&Val); 138a7dea167SDimitry Andric Code.insert(Code.end(), Data, Data + Size); 139*349cc55cSDimitry Andric } 140*349cc55cSDimitry Andric 141*349cc55cSDimitry Andric template <typename T> 142*349cc55cSDimitry Andric static std::enable_if_t<std::is_pointer<T>::value, void> 143*349cc55cSDimitry Andric emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) { 144*349cc55cSDimitry Andric size_t Size = sizeof(uint32_t); 145*349cc55cSDimitry Andric if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 146*349cc55cSDimitry Andric Success = false; 147*349cc55cSDimitry Andric return; 148*349cc55cSDimitry Andric } 149*349cc55cSDimitry Andric 150*349cc55cSDimitry Andric uint32_t ID = P.getOrCreateNativePointer(Val); 151*349cc55cSDimitry Andric const char *Data = reinterpret_cast<const char *>(&ID); 152*349cc55cSDimitry Andric Code.insert(Code.end(), Data, Data + Size); 153*349cc55cSDimitry Andric } 154*349cc55cSDimitry Andric 155*349cc55cSDimitry Andric template <typename... Tys> 156*349cc55cSDimitry Andric bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { 157*349cc55cSDimitry Andric bool Success = true; 158a7dea167SDimitry Andric 159a7dea167SDimitry Andric /// The opcode is followed by arguments. The source info is 160a7dea167SDimitry Andric /// attached to the address after the opcode. 161*349cc55cSDimitry Andric emit(P, Code, Op, Success); 162a7dea167SDimitry Andric if (SI) 163a7dea167SDimitry Andric SrcMap.emplace_back(Code.size(), SI); 164a7dea167SDimitry Andric 165a7dea167SDimitry Andric /// The initializer list forces the expression to be evaluated 166a7dea167SDimitry Andric /// for each argument in the variadic template, in order. 167*349cc55cSDimitry Andric (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...}; 168a7dea167SDimitry Andric 169a7dea167SDimitry Andric return Success; 170a7dea167SDimitry Andric } 171a7dea167SDimitry Andric 172a7dea167SDimitry Andric bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) { 173a7dea167SDimitry Andric return emitJt(getOffset(Label), SourceInfo{}); 174a7dea167SDimitry Andric } 175a7dea167SDimitry Andric 176a7dea167SDimitry Andric bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) { 177a7dea167SDimitry Andric return emitJf(getOffset(Label), SourceInfo{}); 178a7dea167SDimitry Andric } 179a7dea167SDimitry Andric 180a7dea167SDimitry Andric bool ByteCodeEmitter::jump(const LabelTy &Label) { 181a7dea167SDimitry Andric return emitJmp(getOffset(Label), SourceInfo{}); 182a7dea167SDimitry Andric } 183a7dea167SDimitry Andric 184a7dea167SDimitry Andric bool ByteCodeEmitter::fallthrough(const LabelTy &Label) { 185a7dea167SDimitry Andric emitLabel(Label); 186a7dea167SDimitry Andric return true; 187a7dea167SDimitry Andric } 188a7dea167SDimitry Andric 189a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 190a7dea167SDimitry Andric // Opcode emitters 191a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 192a7dea167SDimitry Andric 193a7dea167SDimitry Andric #define GET_LINK_IMPL 194a7dea167SDimitry Andric #include "Opcodes.inc" 195a7dea167SDimitry Andric #undef GET_LINK_IMPL 196