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