• 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 #include "gc_barriers.h"
17 
18 #include "llvm_ark_interface.h"
19 #include "metadata.h"
20 #include "transforms/builtins.h"
21 #include "transforms/runtime_calls.h"
22 
23 #include "compiler/optimizer/ir/basicblock.h"
24 
25 #include <llvm/IR/MDBuilder.h>
26 #include <llvm/ADT/SmallVector.h>
27 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
28 
29 namespace ark::llvmbackend::gc_barriers {
30 
EmitPreWRB(llvm::IRBuilder<> * builder,llvm::Value * mem,bool isVolatileMem,llvm::BasicBlock * outBb,LLVMArkInterface * arkInterface,llvm::Value * threadRegValue)31 void EmitPreWRB(llvm::IRBuilder<> *builder, llvm::Value *mem, bool isVolatileMem, llvm::BasicBlock *outBb,
32                 LLVMArkInterface *arkInterface, llvm::Value *threadRegValue)
33 {
34     auto func = builder->GetInsertBlock()->getParent();
35     auto module = func->getParent();
36     auto &ctx = module->getContext();
37     auto initialBb = builder->GetInsertBlock();
38 
39     auto createUniqBasicBlockName = [&initialBb](const std::string &suffix) {
40         return ark::llvmbackend::LLVMArkInterface::GetUniqueBasicBlockName(initialBb->getName().str(), suffix);
41     };
42     auto createBasicBlock = [&ctx, &initialBb, &createUniqBasicBlockName](const std::string &suffix) {
43         auto name = createUniqBasicBlockName(suffix);
44         auto funcIbb = initialBb->getParent();
45         return llvm::BasicBlock::Create(ctx, name, funcIbb);
46     };
47 
48     auto loadValueBb = createBasicBlock("pre_wrb_load_value");
49     auto callRuntimeBb = createBasicBlock("pre_wrb_call_runtime");
50     auto threadStructPtr = builder->CreateIntToPtr(threadRegValue, builder->getPtrTy());
51     auto entrypointOffset = arkInterface->GetTlsPreWrbEntrypointOffset();
52     auto entrypointPtr = builder->CreateConstInBoundsGEP1_32(builder->getInt8Ty(), threadStructPtr, entrypointOffset);
53 
54     // Check if entrypoint is null
55     auto entrypoint =
56         builder->CreateLoad(builder->getPtrTy(), entrypointPtr, "__panda_entrypoint_PreWrbFuncNoBridge_addr");
57     auto hasEntrypoint = builder->CreateIsNotNull(entrypoint);
58     builder->CreateCondBr(hasEntrypoint, loadValueBb, outBb);
59 
60     // Load old value, similar to LLVMIrConstructor::CreateLoadWithOrdering
61     builder->SetInsertPoint(loadValueBb);
62     auto load = builder->CreateLoad(builder->getPtrTy(LLVMArkInterface::GC_ADDR_SPACE), mem);
63     if (isVolatileMem) {
64         auto alignment = module->getDataLayout().getPrefTypeAlignment(load->getType());
65         load->setOrdering(LLVMArkInterface::VOLATILE_ORDER);
66         load->setAlignment(llvm::Align(alignment));
67     }
68     auto objectIsNull = builder->CreateIsNotNull(load);
69     builder->CreateCondBr(objectIsNull, callRuntimeBb, outBb);
70 
71     // Call Runtime
72     builder->SetInsertPoint(callRuntimeBb);
73     static constexpr auto VAR_ARGS = true;
74     auto functionType =
75         llvm::FunctionType::get(builder->getVoidTy(), {builder->getPtrTy(LLVMArkInterface::GC_ADDR_SPACE)}, !VAR_ARGS);
76     builder->CreateCall(functionType, entrypoint, {load});
77     builder->CreateBr(outBb);
78 
79     builder->SetInsertPoint(outBb);
80 }
81 
EmitPostWRB(llvm::IRBuilder<> * builder,llvm::Value * mem,llvm::Value * offset,llvm::Value * value,LLVMArkInterface * arkInterface,llvm::Value * threadRegValue,llvm::Value * frameRegValue)82 void EmitPostWRB(llvm::IRBuilder<> *builder, llvm::Value *mem, llvm::Value *offset, llvm::Value *value,
83                  LLVMArkInterface *arkInterface, llvm::Value *threadRegValue, llvm::Value *frameRegValue)
84 {
85     auto tlsOffset = arkInterface->GetManagedThreadPostWrbOneObjectOffset();
86 
87     auto gcPtrTy = builder->getPtrTy(LLVMArkInterface::GC_ADDR_SPACE);
88     auto ptrTy = builder->getPtrTy();
89     auto memTy = mem->getType();
90     auto int32Ty = builder->getInt32Ty();
91     auto threadRegPtr = builder->CreateIntToPtr(threadRegValue, ptrTy);
92     auto addr = builder->CreateConstInBoundsGEP1_64(builder->getInt8Ty(), threadRegPtr, tlsOffset);
93     auto callee = builder->CreateLoad(ptrTy, addr, "post_wrb_one_object_addr");
94 
95     ASSERT(mem->getType()->isPointerTy());
96     ASSERT(value->getType()->isPointerTy() &&
97            value->getType()->getPointerAddressSpace() == LLVMArkInterface::GC_ADDR_SPACE);
98 
99     if (!arkInterface->IsIrtocMode()) {
100         // LLVM AOT, only 3 parameters
101         auto funcTy = llvm::FunctionType::get(builder->getVoidTy(), {memTy, int32Ty, gcPtrTy}, false);
102         auto call = builder->CreateCall(funcTy, callee, {mem, offset, value});
103         call->setCallingConv(llvm::CallingConv::ArkFast3);
104         return;
105     }
106     if (arkInterface->IsArm64()) {
107         // Arm64 Irtoc, 4 params (add thread)
108         auto funcTy = llvm::FunctionType::get(builder->getVoidTy(), {memTy, int32Ty, gcPtrTy, ptrTy}, false);
109         auto call = builder->CreateCall(funcTy, callee, {mem, offset, value, threadRegPtr});
110         call->setCallingConv(llvm::CallingConv::ArkFast3);
111         return;
112     }
113     // X86_64 Irtoc, 5 params (add thread, fp)
114     ASSERT(frameRegValue != nullptr);
115     auto funcTy = llvm::FunctionType::get(builder->getVoidTy(), {memTy, int32Ty, gcPtrTy, ptrTy, ptrTy}, false);
116     auto frameRegPtr = builder->CreateIntToPtr(frameRegValue, ptrTy);
117     auto call = builder->CreateCall(funcTy, callee, {mem, offset, value, threadRegPtr, frameRegPtr});
118     call->setCallingConv(llvm::CallingConv::ArkFast3);
119 }
120 
121 }  // namespace ark::llvmbackend::gc_barriers
122