• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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