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 "expand_atomics.h"
17 #include "llvm_ark_interface.h"
18 #include "transforms/transform_utils.h"
19
20 #include <llvm/ADT/STLExtras.h>
21 #include <llvm/IR/Instructions.h>
22
23 #define DEBUG_TYPE "expand-atomics"
24
25 namespace ark::llvmbackend::passes {
26
27 ExpandAtomics::ExpandAtomics() = default;
28
run(llvm::Function & function,llvm::FunctionAnalysisManager & analysisManager)29 llvm::PreservedAnalyses ExpandAtomics::run(llvm::Function &function,
30 [[maybe_unused]] llvm::FunctionAnalysisManager &analysisManager)
31 {
32 bool changed = false;
33
34 if (llvm::Triple {function.getParent()->getTargetTriple()}.getArch() != llvm::Triple::x86_64) {
35 return llvm::PreservedAnalyses::all();
36 }
37
38 for (auto &basicBlock : function) {
39 llvm::SmallVector<llvm::Instruction *> instructions;
40 for (auto &instruction : basicBlock) {
41 if (instruction.isAtomic()) {
42 instructions.push_back(&instruction);
43 }
44 }
45
46 for (auto instruction : instructions) {
47 bool c = InsertAddrSpaceCast(instruction);
48 changed |= c;
49 }
50 }
51
52 return changed ? llvm::PreservedAnalyses::none() : llvm::PreservedAnalyses::all();
53 }
54
InsertAddrSpaceCast(llvm::Instruction * atomicInstruction)55 bool ExpandAtomics::InsertAddrSpaceCast(llvm::Instruction *atomicInstruction)
56 {
57 ASSERT(atomicInstruction->isAtomic());
58 if (llvm::isa<llvm::FenceInst>(atomicInstruction)) {
59 // Fences do not have pointer operands
60 return false;
61 }
62 unsigned pointerIndex = 0;
63 if (llvm::isa<llvm::StoreInst>(atomicInstruction)) {
64 pointerIndex = 1U;
65 }
66 auto pointer = atomicInstruction->getOperand(pointerIndex);
67 ASSERT(pointer->getType()->isPointerTy());
68 if (pointer->getType()->getPointerAddressSpace() != LLVMArkInterface::GC_ADDR_SPACE) {
69 return false;
70 }
71
72 LLVM_DEBUG(llvm::dbgs() << "Inserting addrspacecast for '");
73 LLVM_DEBUG(atomicInstruction->print(llvm::dbgs()));
74 LLVM_DEBUG(llvm::dbgs() << "'\n");
75
76 auto cast = llvm::CastInst::Create(llvm::CastInst::AddrSpaceCast, pointer,
77 llvm::PointerType::get(atomicInstruction->getContext(), 0));
78 cast->insertBefore(atomicInstruction);
79 atomicInstruction->setOperand(pointerIndex, cast);
80
81 LLVM_DEBUG(llvm::dbgs() << "Result: cast = '");
82 LLVM_DEBUG(cast->print(llvm::dbgs()));
83 LLVM_DEBUG(llvm::dbgs() << "', atomic_instruction = '");
84 LLVM_DEBUG(atomicInstruction->print(llvm::dbgs()));
85 LLVM_DEBUG(llvm::dbgs() << "'\n");
86 return true;
87 }
88
89 } // namespace ark::llvmbackend::passes
90