• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "compiler/optimizer/ir/runtime_interface.h"
17 #include "runtime/include/method.h"
18 #include "events/events.h"
19 #include "compiler_options.h"
20 #include "utils/cframe_layout.h"
21 #include "llvm_ark_interface.h"
22 #include "llvm_logger.h"
23 
24 #include <llvm/IR/Function.h>
25 #include <llvm/IR/IntrinsicInst.h>
26 #include <llvm/Support/raw_ostream.h>
27 #include "llvm_options.h"
28 
29 using panda::compiler::RuntimeInterface;
30 
31 namespace {
LLVMArchToArkArch(llvm::Triple::ArchType arch)32 constexpr panda::Arch LLVMArchToArkArch(llvm::Triple::ArchType arch)
33 {
34     switch (arch) {
35         case llvm::Triple::ArchType::aarch64:
36             return panda::Arch::AARCH64;
37         case llvm::Triple::ArchType::x86_64:
38             return panda::Arch::X86_64;
39         case llvm::Triple::ArchType::x86:
40             return panda::Arch::X86;
41         case llvm::Triple::ArchType::arm:
42             return panda::Arch::AARCH32;
43         default:
44             UNREACHABLE();
45             return panda::Arch::NONE;
46     }
47 }
48 #include <entrypoints_gen.inl>
49 #include <intrinsics_gen.inl>
50 #include <intrinsic_names_gen.inl>
51 #include <entrypoints_llvm_ark_interface_gen.inl>
52 }  // namespace
53 
54 namespace panda::llvmbackend {
55 
LLVMArkInterface(RuntimeInterface * runtime,llvm::Triple triple)56 panda::llvmbackend::LLVMArkInterface::LLVMArkInterface(RuntimeInterface *runtime, llvm::Triple triple)
57     : runtime_(runtime), triple_(std::move(triple))
58 {
59     ASSERT(runtime != nullptr);
60 }
61 
GetThreadRegister() const62 const char *LLVMArkInterface::GetThreadRegister() const
63 {
64     switch (LLVMArchToArkArch(triple_.getArch())) {
65         case Arch::AARCH64: {
66             constexpr auto EXPECTED_REGISTER = 28;
67             static_assert(ArchTraits<Arch::AARCH64>::THREAD_REG == EXPECTED_REGISTER);
68             return "x28";
69         }
70         case Arch::X86_64: {
71             constexpr auto EXPECTED_REGISTER = 15;
72             static_assert(ArchTraits<Arch::X86_64>::THREAD_REG == EXPECTED_REGISTER);
73             return "r15";
74         }
75         default:
76             UNREACHABLE();
77     }
78 }
79 
GetFramePointerRegister() const80 const char *LLVMArkInterface::GetFramePointerRegister() const
81 {
82     switch (LLVMArchToArkArch(triple_.getArch())) {
83         case Arch::AARCH64:
84             return "x29";
85         case Arch::X86_64:
86             return "rbp";
87         default:
88             UNREACHABLE();
89     }
90 }
91 
GetEntrypointTlsOffset(EntrypointId id) const92 uintptr_t LLVMArkInterface::GetEntrypointTlsOffset(EntrypointId id) const
93 {
94     Arch arkArch = LLVMArchToArkArch(triple_.getArch());
95     using PandaEntrypointId = panda::compiler::RuntimeInterface::EntrypointId;
96     return runtime_->GetEntrypointTlsOffset(arkArch, static_cast<PandaEntrypointId>(id));
97 }
98 
GetTlsPreWrbEntrypointOffset() const99 size_t LLVMArkInterface::GetTlsPreWrbEntrypointOffset() const
100 {
101     Arch arkArch = LLVMArchToArkArch(triple_.getArch());
102     return runtime_->GetTlsPreWrbEntrypointOffset(arkArch);
103 }
104 
GetManagedThreadPostWrbOneObjectOffset() const105 uint32_t LLVMArkInterface::GetManagedThreadPostWrbOneObjectOffset() const
106 {
107     Arch arkArch = LLVMArchToArkArch(triple_.getArch());
108     return cross_values::GetManagedThreadPostWrbOneObjectOffset(arkArch);
109 }
110 
GetRuntimeFunctionName(LLVMArkInterface::RuntimeCallType callType,LLVMArkInterface::IntrinsicId id)111 llvm::StringRef LLVMArkInterface::GetRuntimeFunctionName(LLVMArkInterface::RuntimeCallType callType,
112                                                          LLVMArkInterface::IntrinsicId id)
113 {
114     if (callType == LLVMArkInterface::RuntimeCallType::INTRINSIC) {
115         return llvm::StringRef(GetIntrinsicRuntimeFunctionName(id));
116     }
117     // sanity check
118     ASSERT(callType == LLVMArkInterface::RuntimeCallType::ENTRYPOINT);
119     return llvm::StringRef(GetEntrypointRuntimeFunctionName(id));
120 }
121 
GetRuntimeFunctionType(llvm::StringRef name) const122 llvm::FunctionType *LLVMArkInterface::GetRuntimeFunctionType(llvm::StringRef name) const
123 {
124     return runtimeFunctionTypes_.lookup(name);
125 }
126 
GetOrCreateRuntimeFunctionType(llvm::LLVMContext & ctx,llvm::Module * module,LLVMArkInterface::RuntimeCallType callType,LLVMArkInterface::IntrinsicId id)127 llvm::FunctionType *LLVMArkInterface::GetOrCreateRuntimeFunctionType(llvm::LLVMContext &ctx, llvm::Module *module,
128                                                                      LLVMArkInterface::RuntimeCallType callType,
129                                                                      LLVMArkInterface::IntrinsicId id)
130 {
131     auto rtFunctionName = GetRuntimeFunctionName(callType, id);
132     auto rtFunctionTy = GetRuntimeFunctionType(rtFunctionName);
133     if (rtFunctionTy != nullptr) {
134         return rtFunctionTy;
135     }
136 
137     if (callType == RuntimeCallType::INTRINSIC) {
138         rtFunctionTy = GetIntrinsicDeclaration(ctx, static_cast<RuntimeInterface::IntrinsicId>(id));
139     } else {
140         // sanity check
141         ASSERT(callType == RuntimeCallType::ENTRYPOINT);
142         rtFunctionTy = GetEntrypointDeclaration(ctx, module, static_cast<RuntimeInterface::EntrypointId>(id));
143     }
144 
145     ASSERT(rtFunctionTy != nullptr);
146     runtimeFunctionTypes_.insert({rtFunctionName, rtFunctionTy});
147     return rtFunctionTy;
148 }
149 
RememberFunctionOrigin(const llvm::Function * function,MethodPtr methodPtr)150 void LLVMArkInterface::RememberFunctionOrigin(const llvm::Function *function, MethodPtr methodPtr)
151 {
152     ASSERT(function != nullptr);
153     ASSERT(methodPtr != nullptr);
154 
155     auto file = static_cast<panda_file::File *>(runtime_->GetBinaryFileForMethod(methodPtr));
156     [[maybe_unused]] auto insertionResult = functionOrigins_.insert({function, file});
157     ASSERT(insertionResult.second);
158     LLVM_LOG(DEBUG, INFRA) << function->getName().data() << " defined in " << runtime_->GetFileName(methodPtr);
159 }
160 
GetEntrypointCallee(EntrypointId id) const161 LLVMArkInterface::RuntimeCallee LLVMArkInterface::GetEntrypointCallee(EntrypointId id) const
162 {
163     using PandaEntrypointId = panda::compiler::RuntimeInterface::EntrypointId;
164     auto eid = static_cast<PandaEntrypointId>(id);
165     auto functionName = GetEntrypointInternalName(eid);
166     auto functionProto = GetRuntimeFunctionType(functionName);
167     ASSERT(functionProto != nullptr);
168     return {functionProto, functionName};
169 }
170 
GetFunctionByMethodPtr(LLVMArkInterface::MethodPtr method) const171 llvm::Function *LLVMArkInterface::GetFunctionByMethodPtr(LLVMArkInterface::MethodPtr method) const
172 {
173     ASSERT(method != nullptr);
174 
175     return functions_.lookup(method);
176 }
177 
PutFunction(LLVMArkInterface::MethodPtr methodPtr,llvm::Function * function)178 void LLVMArkInterface::PutFunction(LLVMArkInterface::MethodPtr methodPtr, llvm::Function *function)
179 {
180     ASSERT(function != nullptr);
181     ASSERT(methodPtr != nullptr);
182     // We are not expecting `tan` functions other than we are adding in LLVMIrConstructor::EmitTan()
183     ASSERT(function->getName() != "tan");
184 
185     [[maybe_unused]] auto fInsertionResult = functions_.insert({methodPtr, function});
186     ASSERT_PRINT(fInsertionResult.first->second == function,
187                  std::string("Attempt to map '") + GetUniqMethodName(methodPtr) + "' to a function = '" +
188                      function->getName().str() + "', but the method_ptr already mapped to '" +
189                      fInsertionResult.first->second->getName().str() + "'");
190     auto sourceLang = static_cast<uint8_t>(runtime_->GetMethodSourceLanguage(methodPtr));
191     [[maybe_unused]] auto slInsertionResult = sourceLanguages_.insert({function, sourceLang});
192     ASSERT(slInsertionResult.first->second == sourceLang);
193 }
194 
GetIntrinsicRuntimeFunctionName(LLVMArkInterface::IntrinsicId id) const195 const char *LLVMArkInterface::GetIntrinsicRuntimeFunctionName(LLVMArkInterface::IntrinsicId id) const
196 {
197     ASSERT(id >= 0 && id < static_cast<IntrinsicId>(RuntimeInterface::IntrinsicId::COUNT));
198     return GetIntrinsicInternalName(static_cast<RuntimeInterface::IntrinsicId>(id));
199 }
200 
GetEntrypointRuntimeFunctionName(LLVMArkInterface::EntrypointId id) const201 const char *LLVMArkInterface::GetEntrypointRuntimeFunctionName(LLVMArkInterface::EntrypointId id) const
202 {
203     ASSERT(id >= 0 && id < static_cast<EntrypointId>(RuntimeInterface::EntrypointId::COUNT));
204     return GetEntrypointInternalName(static_cast<RuntimeInterface::EntrypointId>(id));
205 }
206 
GetUniqMethodName(LLVMArkInterface::MethodPtr methodPtr) const207 std::string LLVMArkInterface::GetUniqMethodName(LLVMArkInterface::MethodPtr methodPtr) const
208 {
209     ASSERT(methodPtr != nullptr);
210 
211     if (IsIrtocMode()) {
212         return runtime_->GetMethodName(methodPtr);
213     }
214 #ifndef NDEBUG
215     auto uniqName = std::string(runtime_->GetMethodFullName(methodPtr, true));
216     uniqName.append("_id_");
217     uniqName.append(std::to_string(runtime_->GetUniqMethodId(methodPtr)));
218 #else
219     std::stringstream ssUniqName;
220     ssUniqName << "f_" << std::hex << methodPtr;
221     auto uniqName = ssUniqName.str();
222 #endif
223     return uniqName;
224 }
225 
GetUniqMethodName(const Method * method) const226 std::string LLVMArkInterface::GetUniqMethodName(const Method *method) const
227 {
228     ASSERT(method != nullptr);
229 
230     auto casted = const_cast<Method *>(method);
231     return GetUniqMethodName(static_cast<MethodPtr>(casted));
232 }
233 
GetUniqueBasicBlockName(const std::string & bbName,const std::string & uniqueSuffix)234 std::string LLVMArkInterface::GetUniqueBasicBlockName(const std::string &bbName, const std::string &uniqueSuffix)
235 {
236     std::stringstream uniqueName;
237     const std::string nameDelimiter = "..";
238     auto first = bbName.find(nameDelimiter);
239     if (first == std::string::npos) {
240         uniqueName << bbName << "_" << uniqueSuffix;
241         return uniqueName.str();
242     }
243 
244     auto second = bbName.rfind(nameDelimiter);
245     ASSERT(second != std::string::npos);
246 
247     uniqueName << bbName.substr(0, first + 2U) << uniqueSuffix << bbName.substr(second, bbName.size());
248 
249     return uniqueName.str();
250 }
251 
IsIrtocMode() const252 bool LLVMArkInterface::IsIrtocMode() const
253 {
254     return true;
255 }
256 
AppendIrtocReturnHandler(llvm::StringRef returnHandler)257 void LLVMArkInterface::AppendIrtocReturnHandler(llvm::StringRef returnHandler)
258 {
259     irtocReturnHandlers_.push_back(returnHandler);
260 }
261 
IsIrtocReturnHandler(const llvm::Function & function) const262 bool LLVMArkInterface::IsIrtocReturnHandler(const llvm::Function &function) const
263 {
264     return std::find(irtocReturnHandlers_.cbegin(), irtocReturnHandlers_.cend(), function.getName()) !=
265            irtocReturnHandlers_.cend();
266 }
267 
268 }  // namespace panda::llvmbackend
269