1 | //===----- RISCVZacasABIFix.cpp -------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This pass implements a fence insertion for an atomic cmpxchg in a case that |
10 | // isn't easy to do with the current AtomicExpandPass hooks API. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "RISCV.h" |
15 | #include "RISCVTargetMachine.h" |
16 | #include "llvm/ADT/Statistic.h" |
17 | #include "llvm/Analysis/ValueTracking.h" |
18 | #include "llvm/CodeGen/TargetPassConfig.h" |
19 | #include "llvm/IR/Dominators.h" |
20 | #include "llvm/IR/IRBuilder.h" |
21 | #include "llvm/IR/InstVisitor.h" |
22 | #include "llvm/IR/Intrinsics.h" |
23 | #include "llvm/InitializePasses.h" |
24 | #include "llvm/Pass.h" |
25 | |
26 | using namespace llvm; |
27 | |
28 | #define DEBUG_TYPE "riscv-zacas-abi-fix" |
29 | #define PASS_NAME "RISC-V Zacas ABI fix" |
30 | |
31 | namespace { |
32 | |
33 | class RISCVZacasABIFix : public FunctionPass, |
34 | public InstVisitor<RISCVZacasABIFix, bool> { |
35 | const RISCVSubtarget *ST; |
36 | |
37 | public: |
38 | static char ID; |
39 | |
40 | RISCVZacasABIFix() : FunctionPass(ID) {} |
41 | |
42 | bool runOnFunction(Function &F) override; |
43 | |
44 | StringRef getPassName() const override { return PASS_NAME; } |
45 | |
46 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
47 | AU.setPreservesCFG(); |
48 | AU.addRequired<TargetPassConfig>(); |
49 | } |
50 | |
51 | bool visitInstruction(Instruction &I) { return false; } |
52 | bool visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); |
53 | }; |
54 | |
55 | } // end anonymous namespace |
56 | |
57 | // Insert a leading fence (needed for broadest atomics ABI compatibility) |
58 | // only if the Zacas extension is enabled and the AtomicCmpXchgInst has a |
59 | // SequentiallyConsistent failure ordering. |
60 | bool RISCVZacasABIFix::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { |
61 | assert(ST->hasStdExtZacas() && "only necessary to run in presence of zacas" ); |
62 | IRBuilder<> Builder(&I); |
63 | if (I.getFailureOrdering() != AtomicOrdering::SequentiallyConsistent) |
64 | return false; |
65 | |
66 | Builder.CreateFence(Ordering: AtomicOrdering::SequentiallyConsistent); |
67 | return true; |
68 | } |
69 | |
70 | bool RISCVZacasABIFix::runOnFunction(Function &F) { |
71 | auto &TPC = getAnalysis<TargetPassConfig>(); |
72 | auto &TM = TPC.getTM<RISCVTargetMachine>(); |
73 | ST = &TM.getSubtarget<RISCVSubtarget>(F); |
74 | |
75 | if (skipFunction(F) || !ST->hasStdExtZacas()) |
76 | return false; |
77 | |
78 | bool MadeChange = false; |
79 | for (auto &BB : F) |
80 | for (Instruction &I : llvm::make_early_inc_range(Range&: BB)) |
81 | MadeChange |= visit(I); |
82 | |
83 | return MadeChange; |
84 | } |
85 | |
86 | INITIALIZE_PASS_BEGIN(RISCVZacasABIFix, DEBUG_TYPE, PASS_NAME, false, false) |
87 | INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) |
88 | INITIALIZE_PASS_END(RISCVZacasABIFix, DEBUG_TYPE, PASS_NAME, false, false) |
89 | |
90 | char RISCVZacasABIFix::ID = 0; |
91 | |
92 | FunctionPass *llvm::createRISCVZacasABIFixPass() { |
93 | return new RISCVZacasABIFix(); |
94 | } |
95 | |