• 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 "gc_barriers.h"
17 
18 #include "llvm_ark_interface.h"
19 #include "metadata.h"
20 
21 #include "compiler/optimizer/ir/basicblock.h"
22 
23 #include <llvm/IR/MDBuilder.h>
24 #include <llvm/ADT/SmallVector.h>
25 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
26 
27 namespace panda::llvmbackend::gc_barriers {
28 
EmitPreWRB(llvm::IRBuilder<> * builder,llvm::Value * mem,bool isVolatileMem,llvm::BasicBlock * outBb,LLVMArkInterface * arkInterface,llvm::Value * threadRegValue)29 void EmitPreWRB(llvm::IRBuilder<> *builder, llvm::Value *mem, bool isVolatileMem, llvm::BasicBlock *outBb,
30                 LLVMArkInterface *arkInterface, llvm::Value *threadRegValue)
31 {
32     auto func = builder->GetInsertBlock()->getParent();
33     auto module = func->getParent();
34     auto &ctx = module->getContext();
35     auto initialBb = builder->GetInsertBlock();
36 
37     auto createUniqBasicBlockName = [&initialBb](const std::string &suffix) {
38         return panda::llvmbackend::LLVMArkInterface::GetUniqueBasicBlockName(initialBb->getName().str(), suffix);
39     };
40     auto createBasicBlock = [&ctx, &initialBb, &createUniqBasicBlockName](const std::string &suffix) {
41         auto name = createUniqBasicBlockName(suffix);
42         auto funcIbb = initialBb->getParent();
43         return llvm::BasicBlock::Create(ctx, name, funcIbb);
44     };
45 
46     auto loadValueBb = createBasicBlock("pre_wrb_load_value");
47     auto callRuntimeBb = createBasicBlock("pre_wrb_call_runtime");
48     auto threadStructPtr = builder->CreateIntToPtr(threadRegValue, builder->getPtrTy());
49     auto entrypointOffset = arkInterface->GetTlsPreWrbEntrypointOffset();
50     auto entrypointPtr = builder->CreateConstInBoundsGEP1_32(builder->getInt8Ty(), threadStructPtr, entrypointOffset);
51 
52     // Check if entrypoint is null
53     auto entrypoint =
54         builder->CreateLoad(builder->getPtrTy(), entrypointPtr, "__panda_entrypoint_PreWrbFuncNoBridge_addr");
55     auto hasEntrypoint = builder->CreateIsNotNull(entrypoint);
56     builder->CreateCondBr(hasEntrypoint, loadValueBb, outBb);
57 
58     // Load old value
59     builder->SetInsertPoint(loadValueBb);
60 
61     // See LLVMEntry::EmitLoad
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 int32Ty = builder->getInt32Ty();
90     auto threadRegPtr = builder->CreateIntToPtr(threadRegValue, ptrTy);
91     auto addr = builder->CreateConstInBoundsGEP1_64(builder->getInt8Ty(), threadRegPtr, tlsOffset);
92     auto callee = builder->CreateLoad(ptrTy, addr, "post_wrb_one_object_addr");
93 
94     if (arkInterface->IsArm64()) {
95         // Arm64 Irtoc, 4 params (add thread)
96         auto funcTy = llvm::FunctionType::get(builder->getVoidTy(), {gcPtrTy, int32Ty, gcPtrTy, ptrTy}, false);
97         auto call = builder->CreateCall(funcTy, callee, {mem, offset, value, threadRegPtr});
98         call->setCallingConv(llvm::CallingConv::ArkFast3);
99         return;
100     }
101     // X86_64 Irtoc, 5 params (add thread, fp)
102     ASSERT(frameRegValue != nullptr);
103     auto funcTy = llvm::FunctionType::get(builder->getVoidTy(), {gcPtrTy, int32Ty, gcPtrTy, ptrTy, ptrTy}, false);
104     auto frameRegPtr = builder->CreateIntToPtr(frameRegValue, ptrTy);
105     auto call = builder->CreateCall(funcTy, callee, {mem, offset, value, threadRegPtr, frameRegPtr});
106     call->setCallingConv(llvm::CallingConv::ArkFast3);
107 }
108 
109 }  // namespace panda::llvmbackend::gc_barriers
110