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