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