1 /* 2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBLLVMBACKEND_LLVM_ARK_INTERFACE_H 17 #define LIBLLVMBACKEND_LLVM_ARK_INTERFACE_H 18 19 #include <map> 20 #include <unordered_map> 21 22 #include <llvm/ADT/DenseMap.h> 23 #include <llvm/ADT/Triple.h> 24 #include <llvm/ADT/StringMap.h> 25 #include <llvm/IR/IRBuilder.h> 26 #include <llvm/IR/ValueMap.h> 27 #include <llvm/IR/Instructions.h> 28 #include <llvm/IR/Intrinsics.h> 29 #include <llvm/IR/IntrinsicInst.h> 30 #include <llvm/Support/AtomicOrdering.h> 31 #include <llvm/Support/Mutex.h> 32 33 namespace llvm { 34 class Function; 35 class FunctionType; 36 class Instruction; 37 class Module; 38 } // namespace llvm 39 40 namespace ark { 41 class Method; 42 } // namespace ark 43 44 namespace ark::compiler { 45 class AotBuilder; 46 class AotData; 47 class RuntimeInterface; 48 class Graph; 49 } // namespace ark::compiler 50 51 namespace ark::panda_file { 52 class File; 53 } // namespace ark::panda_file 54 55 namespace ark::llvmbackend { 56 57 enum class BridgeType { 58 NONE, // 59 ODD_SAVED, // 60 ODD_SAVED1, // 61 ODD_SAVED2, // 62 ODD_SAVED3, // 63 ODD_SAVED4, // 64 ENTRYPOINT, // 65 SLOW_PATH, // 66 }; 67 68 class LLVMArkInterface { 69 public: 70 using MethodPtr = void *; 71 using ClassPtr = void *; 72 using MethodId = uint32_t; 73 using IntrinsicId = int; 74 using EntrypointId = int; 75 using RuntimeCallee = std::pair<llvm::FunctionType *, llvm::StringRef>; 76 using RegMasks = std::tuple<uint32_t, uint32_t>; 77 enum class RuntimeCallType { INTRINSIC, ENTRYPOINT }; 78 79 explicit LLVMArkInterface(ark::compiler::RuntimeInterface *runtime, llvm::Triple triple, 80 ark::compiler::AotBuilder *aotBuilder, llvm::sys::Mutex *lock); 81 82 RuntimeCallee GetEntrypointCallee(EntrypointId id) const; 83 84 void PutCalleeSavedRegistersMask(llvm::StringRef method, RegMasks masks); 85 86 RegMasks GetCalleeSavedRegistersMask(llvm::StringRef method); 87 88 intptr_t GetCompiledEntryPointOffset() const; 89 90 const char *GetThreadRegister() const; 91 const char *GetFramePointerRegister() const; 92 93 uintptr_t GetEntrypointTlsOffset(EntrypointId id) const; 94 size_t GetTlsFrameKindOffset() const; 95 size_t GetTlsPreWrbEntrypointOffset() const; 96 97 void PutVirtualFunction(MethodPtr methodPtr, llvm::Function *function); 98 99 IntrinsicId GetIntrinsicId(const llvm::Instruction *inst) const; 100 llvm::Intrinsic::ID GetLLVMIntrinsicId(const llvm::Instruction *inst) const; 101 102 const char *GetIntrinsicRuntimeFunctionName(LLVMArkInterface::IntrinsicId id) const; 103 const char *GetEntrypointRuntimeFunctionName(LLVMArkInterface::EntrypointId id) const; 104 BridgeType GetBridgeType(EntrypointId id) const; 105 106 llvm::StringRef GetRuntimeFunctionName(LLVMArkInterface::RuntimeCallType callType, IntrinsicId id); 107 llvm::FunctionType *GetRuntimeFunctionType(llvm::StringRef name) const; 108 llvm::FunctionType *GetOrCreateRuntimeFunctionType(llvm::LLVMContext &ctx, llvm::Module *module, 109 LLVMArkInterface::RuntimeCallType callType, IntrinsicId id); 110 #ifndef NDEBUG 111 void MarkAsCompiled(); 112 #endif 113 114 void CreateRequiredIntrinsicFunctionTypes(llvm::LLVMContext &ctx); 115 116 bool IsRememberedCall(const llvm::Function *caller, const llvm::Function *callee) const; 117 void RememberFunctionOrigin(const llvm::Function *function, MethodPtr methodPtr); 118 119 std::string GetUniqMethodName(MethodPtr methodPtr) const; 120 std::string GetUniqMethodName(const Method *method) const; 121 static std::string GetUniqueBasicBlockName(const std::string &bbName, const std::string &uniqueSuffix); 122 123 MethodId GetMethodId(const llvm::Function *caller, const llvm::Function *callee) const; 124 125 uint32_t GetClassOffset() const; 126 uint32_t GetManagedThreadPostWrbOneObjectOffset() const; 127 size_t GetStackOverflowCheckOffset() const; 128 uint32_t GetVTableOffset(llvm::Function *caller, uint32_t methodId) const; 129 130 void RememberFunctionCall(const llvm::Function *caller, const llvm::Function *callee, MethodId methodId); 131 132 int32_t GetPltSlotId(const llvm::Function *caller, const llvm::Function *callee) const; 133 int32_t GetObjectClassOffset() const; 134 int32_t GetClassIndexInAotGot(ark::compiler::AotData *aotData, uint32_t klassId, bool initialized); 135 int32_t GetStringSlotId(ark::compiler::AotData *aotData, uint32_t typeId); 136 uint64_t GetMethodStackSize(MethodPtr method) const; 137 void PutMethodStackSize(const llvm::Function *method, size_t size); 138 uint32_t GetVirtualRegistersCount(MethodPtr method) const; 139 uint32_t GetCFrameHasFloatRegsFlagMask() const; 140 141 bool IsIrtocMode() const; IsArm64()142 bool IsArm64() const 143 { 144 return triple_.getArch() == llvm::Triple::ArchType::aarch64; 145 } 146 147 void AppendIrtocReturnHandler(llvm::StringRef returnHandler); 148 149 bool IsIrtocReturnHandler(const llvm::Function &function) const; 150 151 int32_t CreateIntfInlineCacheSlotId(const llvm::Function *caller) const; 152 153 MethodPtr ResolveVirtual(uint32_t classId, llvm::CallInst *call); 154 bool IsInterfaceMethod(llvm::CallInst *call); 155 bool IsExternal(llvm::CallInst *call); 156 157 public: 158 static constexpr auto NO_INTRINSIC_ID = static_cast<IntrinsicId>(-1); 159 static constexpr auto GC_ADDR_SPACE = 271; 160 static constexpr auto VOLATILE_ORDER = llvm::AtomicOrdering::SequentiallyConsistent; 161 static constexpr auto NOT_ATOMIC_ORDER = llvm::AtomicOrdering::NotAtomic; 162 static constexpr std::string_view GC_SAFEPOINT_POLL_NAME = "gc.safepoint_poll"; 163 static constexpr std::string_view GC_STRATEGY = "ark"; 164 static constexpr std::string_view FUNCTION_MD_CLASS_ID = "class_id"; 165 static constexpr std::string_view FUNCTION_MD_INLINE_MODULE = "inline_module"; 166 static constexpr std::string_view PATCH_STACK_ADJUSTMENT_COMMENT = " ${:comment} patch-stack-adjustment"; 167 static constexpr std::string_view AARCH64_SDIV_INST = "aarch64_sdiv"; 168 static constexpr std::string_view SOURCE_LANG_ATTR = "source-language"; 169 GetRuntime()170 ark::compiler::RuntimeInterface *GetRuntime() 171 { 172 return runtime_; 173 } 174 175 bool DeoptsEnabled(); 176 177 // Convert given dwarfReg id into Ark register id 178 // For dwarf numbering see https://www.ucw.cz/~hubicka/papers/abi/node14.html 179 // For Ark see static_core/compiler/optimizer/code_generator/target_info.h X86RegNumberConvert(size_t dwarfReg)180 static constexpr size_t X86RegNumberConvert(size_t dwarfReg) 181 { 182 constexpr size_t RAX = 0U; // dwarf 0 183 constexpr size_t RDX = 2U; // dwarf 1 184 constexpr size_t RCX = 1U; // dwarf 2 185 constexpr size_t RBX = 11U; // dwarf 3 186 constexpr size_t RSI = 6U; // dwarf 4 187 constexpr size_t RDI = 7U; // dwarf 5 188 constexpr size_t RBP = 9U; // dwarf 6 189 constexpr size_t RSP = 10U; // dwarf 7 190 constexpr size_t R8 = 8U; // dwarf 8 191 constexpr size_t R9 = 5U; // dwarf 9 192 constexpr size_t R10 = 4U; // dwarf 10 193 constexpr size_t R11 = 3U; // dwarf 11 194 constexpr size_t R12 = 12U; // dwarf 12 195 196 constexpr std::array TO_ARK = {RAX, RDX, RCX, RBX, RSI, RDI, RBP, RSP, R8, R9, R10, R11}; 197 return dwarfReg >= R12 ? dwarfReg : TO_ARK[dwarfReg]; 198 } 199 200 // Convert given Ark register id to dwarf register id ToDwarfRegNumX86(size_t arkReg)201 static constexpr size_t ToDwarfRegNumX86(size_t arkReg) 202 { 203 constexpr size_t RAX = 0U; // Ark 0 204 constexpr size_t RCX = 2U; // Ark 1 205 constexpr size_t RDX = 1U; // Ark 2 206 constexpr size_t R11 = 11U; // Ark 3 207 constexpr size_t R10 = 10U; // Ark 4 208 constexpr size_t R9 = 9U; // Ark 5 209 constexpr size_t RSI = 4U; // Ark 6 210 constexpr size_t RDI = 5U; // Ark 7 211 constexpr size_t R8 = 8U; // Ark 8 212 constexpr size_t RBP = 6U; // Ark 9 213 constexpr size_t RSP = 7U; // Ark 10 214 constexpr size_t RBX = 3U; // Ark 11 215 constexpr size_t R12 = 12U; // Ark 12 216 217 constexpr std::array TO_DWARF = {RAX, RCX, RDX, R11, R10, R9, RSI, RDI, R8, RBP, RSP, RBX}; 218 return arkReg >= R12 ? arkReg : TO_DWARF[arkReg]; 219 } 220 221 private: 222 IntrinsicId GetPluginIntrinsicId(const llvm::Instruction *instruction) const; 223 IntrinsicId GetIntrinsicIdSwitch(const llvm::IntrinsicInst *inst) const; 224 IntrinsicId GetIntrinsicIdMemory(const llvm::IntrinsicInst *inst) const; 225 IntrinsicId GetIntrinsicIdMath(const llvm::IntrinsicInst *inst) const; 226 #include "get_intrinsic_id_llvm_ark_interface_gen.h.inl" 227 private: 228 static constexpr auto NO_INTRINSIC_ID_CONTINUE = static_cast<IntrinsicId>(-2); 229 230 ark::compiler::RuntimeInterface *runtime_; 231 llvm::Triple triple_; 232 llvm::StringMap<llvm::FunctionType *> runtimeFunctionTypes_; 233 llvm::StringMap<const panda_file::File *> functionOrigins_; 234 llvm::DenseMap<const panda_file::File *, llvm::StringMap<MethodId>> methodIds_; 235 llvm::StringMap<MethodPtr> methodPtrs_; 236 llvm::StringMap<uint64_t> llvmStackSizes_; 237 llvm::StringMap<RegMasks> calleeSavedRegisters_; 238 ark::compiler::AotBuilder *aotBuilder_; 239 std::vector<llvm::StringRef> irtocReturnHandlers_; 240 mutable llvm::sys::Mutex *lock_; 241 #ifndef NDEBUG 242 bool compiled_ = false; 243 #endif 244 }; 245 } // namespace ark::llvmbackend 246 #endif // LIBLLVMBACKEND_LLVM_ARK_INTERFACE_H 247