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