1 /*
2 * Copyright (c) 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 #include "libpandabase/macros.h"
17 #include "utils.h"
18
19 namespace ark::llvmbackend::utils {
20
GetMethodIdFromAttr(llvm::CallInst * call)21 int64_t GetMethodIdFromAttr(llvm::CallInst *call)
22 {
23 ASSERT(call != nullptr);
24 ASSERT(call->hasFnAttr("original-method-id"));
25 auto attr = call->getFnAttr("original-method-id");
26 int64_t integer = -1;
27 [[maybe_unused]] auto error = attr.getValueAsString().getAsInteger(0, integer);
28 ASSERT(!error);
29 ASSERT(integer >= 0);
30 return integer;
31 }
32
HasCallsWithDeopt(llvm::Function & func)33 bool HasCallsWithDeopt(llvm::Function &func)
34 {
35 for (auto &block : func) {
36 for (auto &instruction : block) {
37 auto call = llvm::dyn_cast<llvm::CallInst>(&instruction);
38 if (call != nullptr && call->getOperandBundle(llvm::LLVMContext::OB_deopt)) {
39 return true;
40 }
41 }
42 }
43 return false;
44 }
45
CopyDeoptBundle(llvm::CallInst * from)46 llvm::SmallVector<llvm::OperandBundleDef> CopyDeoptBundle(llvm::CallInst *from)
47 {
48 llvm::SmallVector<llvm::OperandBundleDef, 1> bundles;
49 auto deoptBundle = from->getOperandBundle(llvm::LLVMContext::OB_deopt);
50 if (deoptBundle) {
51 llvm::SmallVector<llvm::Value *, 0> deoptVals;
52 for (auto &user : deoptBundle->Inputs) {
53 deoptVals.push_back(user.get());
54 }
55 bundles.push_back(llvm::OperandBundleDef {"deopt", deoptVals});
56 }
57 return bundles;
58 }
59
CopyDebugLoc(llvm::CallInst * from,llvm::CallInst * to)60 void CopyDebugLoc(llvm::CallInst *from, llvm::CallInst *to)
61 {
62 auto &debugLoc = from->getDebugLoc();
63 auto line = debugLoc ? debugLoc.getLine() : 0;
64 auto inlinedAt = debugLoc ? debugLoc.getInlinedAt() : nullptr;
65 auto func = from->getParent()->getParent();
66 to->setDebugLoc(llvm::DILocation::get(func->getContext(), line, 1, func->getSubprogram(), inlinedAt));
67 }
68
CreateLoadClassFromObject(llvm::Value * object,llvm::IRBuilder<> * builder,ark::llvmbackend::LLVMArkInterface * arkInterface)69 llvm::Value *CreateLoadClassFromObject(llvm::Value *object, llvm::IRBuilder<> *builder,
70 ark::llvmbackend::LLVMArkInterface *arkInterface)
71 {
72 ASSERT(object->getType()->isPointerTy());
73
74 auto dataOff = arkInterface->GetObjectClassOffset();
75 auto ptrData = builder->CreateConstInBoundsGEP1_32(builder->getInt8Ty(), object, dataOff);
76 auto classAddress = builder->CreateLoad(builder->getInt32Ty(), ptrData);
77 return builder->CreateIntToPtr(classAddress, builder->getPtrTy());
78 }
79
CreateLoadMethodUsingVTable(llvm::Value * thiz,llvm::Function * caller,size_t methodId,llvm::IRBuilder<> * builder,LLVMArkInterface * arkInterface)80 llvm::Value *CreateLoadMethodUsingVTable(llvm::Value *thiz, llvm::Function *caller, size_t methodId,
81 llvm::IRBuilder<> *builder, LLVMArkInterface *arkInterface)
82 {
83 ASSERT(thiz != nullptr);
84 ASSERT(caller != nullptr);
85
86 auto classPtr = CreateLoadClassFromObject(thiz, builder, arkInterface);
87 auto offset = arkInterface->GetVTableOffset(caller, methodId);
88 auto methodPtr = builder->CreateConstInBoundsGEP1_32(builder->getInt8Ty(), classPtr, offset);
89 return builder->CreateLoad(builder->getPtrTy(), methodPtr);
90 }
91
92 } // namespace ark::llvmbackend::utils
93