xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVExpandAtomicPseudoInsts.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===-- RISCVExpandAtomicPseudoInsts.cpp - Expand atomic pseudo instrs. ---===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric //
9*5ffd83dbSDimitry Andric // This file contains a pass that expands atomic pseudo instructions into
10*5ffd83dbSDimitry Andric // target instructions. This pass should be run at the last possible moment,
11*5ffd83dbSDimitry Andric // avoiding the possibility for other passes to break the requirements for
12*5ffd83dbSDimitry Andric // forward progress in the LR/SC block.
13*5ffd83dbSDimitry Andric //
14*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
15*5ffd83dbSDimitry Andric 
16*5ffd83dbSDimitry Andric #include "RISCV.h"
17*5ffd83dbSDimitry Andric #include "RISCVInstrInfo.h"
18*5ffd83dbSDimitry Andric #include "RISCVTargetMachine.h"
19*5ffd83dbSDimitry Andric 
20*5ffd83dbSDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
21*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
22*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
23*5ffd83dbSDimitry Andric 
24*5ffd83dbSDimitry Andric using namespace llvm;
25*5ffd83dbSDimitry Andric 
26*5ffd83dbSDimitry Andric #define RISCV_EXPAND_ATOMIC_PSEUDO_NAME                                        \
27*5ffd83dbSDimitry Andric   "RISCV atomic pseudo instruction expansion pass"
28*5ffd83dbSDimitry Andric 
29*5ffd83dbSDimitry Andric namespace {
30*5ffd83dbSDimitry Andric 
31*5ffd83dbSDimitry Andric class RISCVExpandAtomicPseudo : public MachineFunctionPass {
32*5ffd83dbSDimitry Andric public:
33*5ffd83dbSDimitry Andric   const RISCVInstrInfo *TII;
34*5ffd83dbSDimitry Andric   static char ID;
35*5ffd83dbSDimitry Andric 
36*5ffd83dbSDimitry Andric   RISCVExpandAtomicPseudo() : MachineFunctionPass(ID) {
37*5ffd83dbSDimitry Andric     initializeRISCVExpandAtomicPseudoPass(*PassRegistry::getPassRegistry());
38*5ffd83dbSDimitry Andric   }
39*5ffd83dbSDimitry Andric 
40*5ffd83dbSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
41*5ffd83dbSDimitry Andric 
42*5ffd83dbSDimitry Andric   StringRef getPassName() const override {
43*5ffd83dbSDimitry Andric     return RISCV_EXPAND_ATOMIC_PSEUDO_NAME;
44*5ffd83dbSDimitry Andric   }
45*5ffd83dbSDimitry Andric 
46*5ffd83dbSDimitry Andric private:
47*5ffd83dbSDimitry Andric   bool expandMBB(MachineBasicBlock &MBB);
48*5ffd83dbSDimitry Andric   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
49*5ffd83dbSDimitry Andric                 MachineBasicBlock::iterator &NextMBBI);
50*5ffd83dbSDimitry Andric   bool expandAtomicBinOp(MachineBasicBlock &MBB,
51*5ffd83dbSDimitry Andric                          MachineBasicBlock::iterator MBBI, AtomicRMWInst::BinOp,
52*5ffd83dbSDimitry Andric                          bool IsMasked, int Width,
53*5ffd83dbSDimitry Andric                          MachineBasicBlock::iterator &NextMBBI);
54*5ffd83dbSDimitry Andric   bool expandAtomicMinMaxOp(MachineBasicBlock &MBB,
55*5ffd83dbSDimitry Andric                             MachineBasicBlock::iterator MBBI,
56*5ffd83dbSDimitry Andric                             AtomicRMWInst::BinOp, bool IsMasked, int Width,
57*5ffd83dbSDimitry Andric                             MachineBasicBlock::iterator &NextMBBI);
58*5ffd83dbSDimitry Andric   bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
59*5ffd83dbSDimitry Andric                            MachineBasicBlock::iterator MBBI, bool IsMasked,
60*5ffd83dbSDimitry Andric                            int Width, MachineBasicBlock::iterator &NextMBBI);
61*5ffd83dbSDimitry Andric };
62*5ffd83dbSDimitry Andric 
63*5ffd83dbSDimitry Andric char RISCVExpandAtomicPseudo::ID = 0;
64*5ffd83dbSDimitry Andric 
65*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::runOnMachineFunction(MachineFunction &MF) {
66*5ffd83dbSDimitry Andric   TII = static_cast<const RISCVInstrInfo *>(MF.getSubtarget().getInstrInfo());
67*5ffd83dbSDimitry Andric   bool Modified = false;
68*5ffd83dbSDimitry Andric   for (auto &MBB : MF)
69*5ffd83dbSDimitry Andric     Modified |= expandMBB(MBB);
70*5ffd83dbSDimitry Andric   return Modified;
71*5ffd83dbSDimitry Andric }
72*5ffd83dbSDimitry Andric 
73*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMBB(MachineBasicBlock &MBB) {
74*5ffd83dbSDimitry Andric   bool Modified = false;
75*5ffd83dbSDimitry Andric 
76*5ffd83dbSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
77*5ffd83dbSDimitry Andric   while (MBBI != E) {
78*5ffd83dbSDimitry Andric     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
79*5ffd83dbSDimitry Andric     Modified |= expandMI(MBB, MBBI, NMBBI);
80*5ffd83dbSDimitry Andric     MBBI = NMBBI;
81*5ffd83dbSDimitry Andric   }
82*5ffd83dbSDimitry Andric 
83*5ffd83dbSDimitry Andric   return Modified;
84*5ffd83dbSDimitry Andric }
85*5ffd83dbSDimitry Andric 
86*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMI(MachineBasicBlock &MBB,
87*5ffd83dbSDimitry Andric                                        MachineBasicBlock::iterator MBBI,
88*5ffd83dbSDimitry Andric                                        MachineBasicBlock::iterator &NextMBBI) {
89*5ffd83dbSDimitry Andric   // RISCVInstrInfo::getInstSizeInBytes hard-codes the number of expanded
90*5ffd83dbSDimitry Andric   // instructions for each pseudo, and must be updated when adding new pseudos
91*5ffd83dbSDimitry Andric   // or changing existing ones.
92*5ffd83dbSDimitry Andric   switch (MBBI->getOpcode()) {
93*5ffd83dbSDimitry Andric   case RISCV::PseudoAtomicLoadNand32:
94*5ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 32,
95*5ffd83dbSDimitry Andric                              NextMBBI);
96*5ffd83dbSDimitry Andric   case RISCV::PseudoAtomicLoadNand64:
97*5ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 64,
98*5ffd83dbSDimitry Andric                              NextMBBI);
99*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicSwap32:
100*5ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, true, 32,
101*5ffd83dbSDimitry Andric                              NextMBBI);
102*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadAdd32:
103*5ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Add, true, 32, NextMBBI);
104*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadSub32:
105*5ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Sub, true, 32, NextMBBI);
106*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadNand32:
107*5ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, true, 32,
108*5ffd83dbSDimitry Andric                              NextMBBI);
109*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadMax32:
110*5ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Max, true, 32,
111*5ffd83dbSDimitry Andric                                 NextMBBI);
112*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadMin32:
113*5ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Min, true, 32,
114*5ffd83dbSDimitry Andric                                 NextMBBI);
115*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadUMax32:
116*5ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMax, true, 32,
117*5ffd83dbSDimitry Andric                                 NextMBBI);
118*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadUMin32:
119*5ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, true, 32,
120*5ffd83dbSDimitry Andric                                 NextMBBI);
121*5ffd83dbSDimitry Andric   case RISCV::PseudoCmpXchg32:
122*5ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, false, 32, NextMBBI);
123*5ffd83dbSDimitry Andric   case RISCV::PseudoCmpXchg64:
124*5ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
125*5ffd83dbSDimitry Andric   case RISCV::PseudoMaskedCmpXchg32:
126*5ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
127*5ffd83dbSDimitry Andric   }
128*5ffd83dbSDimitry Andric 
129*5ffd83dbSDimitry Andric   return false;
130*5ffd83dbSDimitry Andric }
131*5ffd83dbSDimitry Andric 
132*5ffd83dbSDimitry Andric static unsigned getLRForRMW32(AtomicOrdering Ordering) {
133*5ffd83dbSDimitry Andric   switch (Ordering) {
134*5ffd83dbSDimitry Andric   default:
135*5ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
136*5ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
137*5ffd83dbSDimitry Andric     return RISCV::LR_W;
138*5ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
139*5ffd83dbSDimitry Andric     return RISCV::LR_W_AQ;
140*5ffd83dbSDimitry Andric   case AtomicOrdering::Release:
141*5ffd83dbSDimitry Andric     return RISCV::LR_W;
142*5ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
143*5ffd83dbSDimitry Andric     return RISCV::LR_W_AQ;
144*5ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
145*5ffd83dbSDimitry Andric     return RISCV::LR_W_AQ_RL;
146*5ffd83dbSDimitry Andric   }
147*5ffd83dbSDimitry Andric }
148*5ffd83dbSDimitry Andric 
149*5ffd83dbSDimitry Andric static unsigned getSCForRMW32(AtomicOrdering Ordering) {
150*5ffd83dbSDimitry Andric   switch (Ordering) {
151*5ffd83dbSDimitry Andric   default:
152*5ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
153*5ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
154*5ffd83dbSDimitry Andric     return RISCV::SC_W;
155*5ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
156*5ffd83dbSDimitry Andric     return RISCV::SC_W;
157*5ffd83dbSDimitry Andric   case AtomicOrdering::Release:
158*5ffd83dbSDimitry Andric     return RISCV::SC_W_RL;
159*5ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
160*5ffd83dbSDimitry Andric     return RISCV::SC_W_RL;
161*5ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
162*5ffd83dbSDimitry Andric     return RISCV::SC_W_AQ_RL;
163*5ffd83dbSDimitry Andric   }
164*5ffd83dbSDimitry Andric }
165*5ffd83dbSDimitry Andric 
166*5ffd83dbSDimitry Andric static unsigned getLRForRMW64(AtomicOrdering Ordering) {
167*5ffd83dbSDimitry Andric   switch (Ordering) {
168*5ffd83dbSDimitry Andric   default:
169*5ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
170*5ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
171*5ffd83dbSDimitry Andric     return RISCV::LR_D;
172*5ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
173*5ffd83dbSDimitry Andric     return RISCV::LR_D_AQ;
174*5ffd83dbSDimitry Andric   case AtomicOrdering::Release:
175*5ffd83dbSDimitry Andric     return RISCV::LR_D;
176*5ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
177*5ffd83dbSDimitry Andric     return RISCV::LR_D_AQ;
178*5ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
179*5ffd83dbSDimitry Andric     return RISCV::LR_D_AQ_RL;
180*5ffd83dbSDimitry Andric   }
181*5ffd83dbSDimitry Andric }
182*5ffd83dbSDimitry Andric 
183*5ffd83dbSDimitry Andric static unsigned getSCForRMW64(AtomicOrdering Ordering) {
184*5ffd83dbSDimitry Andric   switch (Ordering) {
185*5ffd83dbSDimitry Andric   default:
186*5ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
187*5ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
188*5ffd83dbSDimitry Andric     return RISCV::SC_D;
189*5ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
190*5ffd83dbSDimitry Andric     return RISCV::SC_D;
191*5ffd83dbSDimitry Andric   case AtomicOrdering::Release:
192*5ffd83dbSDimitry Andric     return RISCV::SC_D_RL;
193*5ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
194*5ffd83dbSDimitry Andric     return RISCV::SC_D_RL;
195*5ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
196*5ffd83dbSDimitry Andric     return RISCV::SC_D_AQ_RL;
197*5ffd83dbSDimitry Andric   }
198*5ffd83dbSDimitry Andric }
199*5ffd83dbSDimitry Andric 
200*5ffd83dbSDimitry Andric static unsigned getLRForRMW(AtomicOrdering Ordering, int Width) {
201*5ffd83dbSDimitry Andric   if (Width == 32)
202*5ffd83dbSDimitry Andric     return getLRForRMW32(Ordering);
203*5ffd83dbSDimitry Andric   if (Width == 64)
204*5ffd83dbSDimitry Andric     return getLRForRMW64(Ordering);
205*5ffd83dbSDimitry Andric   llvm_unreachable("Unexpected LR width\n");
206*5ffd83dbSDimitry Andric }
207*5ffd83dbSDimitry Andric 
208*5ffd83dbSDimitry Andric static unsigned getSCForRMW(AtomicOrdering Ordering, int Width) {
209*5ffd83dbSDimitry Andric   if (Width == 32)
210*5ffd83dbSDimitry Andric     return getSCForRMW32(Ordering);
211*5ffd83dbSDimitry Andric   if (Width == 64)
212*5ffd83dbSDimitry Andric     return getSCForRMW64(Ordering);
213*5ffd83dbSDimitry Andric   llvm_unreachable("Unexpected SC width\n");
214*5ffd83dbSDimitry Andric }
215*5ffd83dbSDimitry Andric 
216*5ffd83dbSDimitry Andric static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI,
217*5ffd83dbSDimitry Andric                                    DebugLoc DL, MachineBasicBlock *ThisMBB,
218*5ffd83dbSDimitry Andric                                    MachineBasicBlock *LoopMBB,
219*5ffd83dbSDimitry Andric                                    MachineBasicBlock *DoneMBB,
220*5ffd83dbSDimitry Andric                                    AtomicRMWInst::BinOp BinOp, int Width) {
221*5ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
222*5ffd83dbSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
223*5ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
224*5ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(3).getReg();
225*5ffd83dbSDimitry Andric   AtomicOrdering Ordering =
226*5ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(4).getImm());
227*5ffd83dbSDimitry Andric 
228*5ffd83dbSDimitry Andric   // .loop:
229*5ffd83dbSDimitry Andric   //   lr.[w|d] dest, (addr)
230*5ffd83dbSDimitry Andric   //   binop scratch, dest, val
231*5ffd83dbSDimitry Andric   //   sc.[w|d] scratch, scratch, (addr)
232*5ffd83dbSDimitry Andric   //   bnez scratch, loop
233*5ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
234*5ffd83dbSDimitry Andric       .addReg(AddrReg);
235*5ffd83dbSDimitry Andric   switch (BinOp) {
236*5ffd83dbSDimitry Andric   default:
237*5ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
238*5ffd83dbSDimitry Andric   case AtomicRMWInst::Nand:
239*5ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
240*5ffd83dbSDimitry Andric         .addReg(DestReg)
241*5ffd83dbSDimitry Andric         .addReg(IncrReg);
242*5ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
243*5ffd83dbSDimitry Andric         .addReg(ScratchReg)
244*5ffd83dbSDimitry Andric         .addImm(-1);
245*5ffd83dbSDimitry Andric     break;
246*5ffd83dbSDimitry Andric   }
247*5ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
248*5ffd83dbSDimitry Andric       .addReg(AddrReg)
249*5ffd83dbSDimitry Andric       .addReg(ScratchReg);
250*5ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
251*5ffd83dbSDimitry Andric       .addReg(ScratchReg)
252*5ffd83dbSDimitry Andric       .addReg(RISCV::X0)
253*5ffd83dbSDimitry Andric       .addMBB(LoopMBB);
254*5ffd83dbSDimitry Andric }
255*5ffd83dbSDimitry Andric 
256*5ffd83dbSDimitry Andric static void insertMaskedMerge(const RISCVInstrInfo *TII, DebugLoc DL,
257*5ffd83dbSDimitry Andric                               MachineBasicBlock *MBB, Register DestReg,
258*5ffd83dbSDimitry Andric                               Register OldValReg, Register NewValReg,
259*5ffd83dbSDimitry Andric                               Register MaskReg, Register ScratchReg) {
260*5ffd83dbSDimitry Andric   assert(OldValReg != ScratchReg && "OldValReg and ScratchReg must be unique");
261*5ffd83dbSDimitry Andric   assert(OldValReg != MaskReg && "OldValReg and MaskReg must be unique");
262*5ffd83dbSDimitry Andric   assert(ScratchReg != MaskReg && "ScratchReg and MaskReg must be unique");
263*5ffd83dbSDimitry Andric 
264*5ffd83dbSDimitry Andric   // We select bits from newval and oldval using:
265*5ffd83dbSDimitry Andric   // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
266*5ffd83dbSDimitry Andric   // r = oldval ^ ((oldval ^ newval) & masktargetdata);
267*5ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::XOR), ScratchReg)
268*5ffd83dbSDimitry Andric       .addReg(OldValReg)
269*5ffd83dbSDimitry Andric       .addReg(NewValReg);
270*5ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::AND), ScratchReg)
271*5ffd83dbSDimitry Andric       .addReg(ScratchReg)
272*5ffd83dbSDimitry Andric       .addReg(MaskReg);
273*5ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::XOR), DestReg)
274*5ffd83dbSDimitry Andric       .addReg(OldValReg)
275*5ffd83dbSDimitry Andric       .addReg(ScratchReg);
276*5ffd83dbSDimitry Andric }
277*5ffd83dbSDimitry Andric 
278*5ffd83dbSDimitry Andric static void doMaskedAtomicBinOpExpansion(
279*5ffd83dbSDimitry Andric     const RISCVInstrInfo *TII, MachineInstr &MI, DebugLoc DL,
280*5ffd83dbSDimitry Andric     MachineBasicBlock *ThisMBB, MachineBasicBlock *LoopMBB,
281*5ffd83dbSDimitry Andric     MachineBasicBlock *DoneMBB, AtomicRMWInst::BinOp BinOp, int Width) {
282*5ffd83dbSDimitry Andric   assert(Width == 32 && "Should never need to expand masked 64-bit operations");
283*5ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
284*5ffd83dbSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
285*5ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
286*5ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(3).getReg();
287*5ffd83dbSDimitry Andric   Register MaskReg = MI.getOperand(4).getReg();
288*5ffd83dbSDimitry Andric   AtomicOrdering Ordering =
289*5ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(5).getImm());
290*5ffd83dbSDimitry Andric 
291*5ffd83dbSDimitry Andric   // .loop:
292*5ffd83dbSDimitry Andric   //   lr.w destreg, (alignedaddr)
293*5ffd83dbSDimitry Andric   //   binop scratch, destreg, incr
294*5ffd83dbSDimitry Andric   //   xor scratch, destreg, scratch
295*5ffd83dbSDimitry Andric   //   and scratch, scratch, masktargetdata
296*5ffd83dbSDimitry Andric   //   xor scratch, destreg, scratch
297*5ffd83dbSDimitry Andric   //   sc.w scratch, scratch, (alignedaddr)
298*5ffd83dbSDimitry Andric   //   bnez scratch, loop
299*5ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
300*5ffd83dbSDimitry Andric       .addReg(AddrReg);
301*5ffd83dbSDimitry Andric   switch (BinOp) {
302*5ffd83dbSDimitry Andric   default:
303*5ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
304*5ffd83dbSDimitry Andric   case AtomicRMWInst::Xchg:
305*5ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::ADDI), ScratchReg)
306*5ffd83dbSDimitry Andric         .addReg(IncrReg)
307*5ffd83dbSDimitry Andric         .addImm(0);
308*5ffd83dbSDimitry Andric     break;
309*5ffd83dbSDimitry Andric   case AtomicRMWInst::Add:
310*5ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg)
311*5ffd83dbSDimitry Andric         .addReg(DestReg)
312*5ffd83dbSDimitry Andric         .addReg(IncrReg);
313*5ffd83dbSDimitry Andric     break;
314*5ffd83dbSDimitry Andric   case AtomicRMWInst::Sub:
315*5ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::SUB), ScratchReg)
316*5ffd83dbSDimitry Andric         .addReg(DestReg)
317*5ffd83dbSDimitry Andric         .addReg(IncrReg);
318*5ffd83dbSDimitry Andric     break;
319*5ffd83dbSDimitry Andric   case AtomicRMWInst::Nand:
320*5ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
321*5ffd83dbSDimitry Andric         .addReg(DestReg)
322*5ffd83dbSDimitry Andric         .addReg(IncrReg);
323*5ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
324*5ffd83dbSDimitry Andric         .addReg(ScratchReg)
325*5ffd83dbSDimitry Andric         .addImm(-1);
326*5ffd83dbSDimitry Andric     break;
327*5ffd83dbSDimitry Andric   }
328*5ffd83dbSDimitry Andric 
329*5ffd83dbSDimitry Andric   insertMaskedMerge(TII, DL, LoopMBB, ScratchReg, DestReg, ScratchReg, MaskReg,
330*5ffd83dbSDimitry Andric                     ScratchReg);
331*5ffd83dbSDimitry Andric 
332*5ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg)
333*5ffd83dbSDimitry Andric       .addReg(AddrReg)
334*5ffd83dbSDimitry Andric       .addReg(ScratchReg);
335*5ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
336*5ffd83dbSDimitry Andric       .addReg(ScratchReg)
337*5ffd83dbSDimitry Andric       .addReg(RISCV::X0)
338*5ffd83dbSDimitry Andric       .addMBB(LoopMBB);
339*5ffd83dbSDimitry Andric }
340*5ffd83dbSDimitry Andric 
341*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicBinOp(
342*5ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
343*5ffd83dbSDimitry Andric     AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
344*5ffd83dbSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
345*5ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
346*5ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
347*5ffd83dbSDimitry Andric 
348*5ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
349*5ffd83dbSDimitry Andric   auto LoopMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
350*5ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
351*5ffd83dbSDimitry Andric 
352*5ffd83dbSDimitry Andric   // Insert new MBBs.
353*5ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopMBB);
354*5ffd83dbSDimitry Andric   MF->insert(++LoopMBB->getIterator(), DoneMBB);
355*5ffd83dbSDimitry Andric 
356*5ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
357*5ffd83dbSDimitry Andric   LoopMBB->addSuccessor(LoopMBB);
358*5ffd83dbSDimitry Andric   LoopMBB->addSuccessor(DoneMBB);
359*5ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
360*5ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
361*5ffd83dbSDimitry Andric   MBB.addSuccessor(LoopMBB);
362*5ffd83dbSDimitry Andric 
363*5ffd83dbSDimitry Andric   if (!IsMasked)
364*5ffd83dbSDimitry Andric     doAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp, Width);
365*5ffd83dbSDimitry Andric   else
366*5ffd83dbSDimitry Andric     doMaskedAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp,
367*5ffd83dbSDimitry Andric                                  Width);
368*5ffd83dbSDimitry Andric 
369*5ffd83dbSDimitry Andric   NextMBBI = MBB.end();
370*5ffd83dbSDimitry Andric   MI.eraseFromParent();
371*5ffd83dbSDimitry Andric 
372*5ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
373*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopMBB);
374*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
375*5ffd83dbSDimitry Andric 
376*5ffd83dbSDimitry Andric   return true;
377*5ffd83dbSDimitry Andric }
378*5ffd83dbSDimitry Andric 
379*5ffd83dbSDimitry Andric static void insertSext(const RISCVInstrInfo *TII, DebugLoc DL,
380*5ffd83dbSDimitry Andric                        MachineBasicBlock *MBB, Register ValReg,
381*5ffd83dbSDimitry Andric                        Register ShamtReg) {
382*5ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::SLL), ValReg)
383*5ffd83dbSDimitry Andric       .addReg(ValReg)
384*5ffd83dbSDimitry Andric       .addReg(ShamtReg);
385*5ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::SRA), ValReg)
386*5ffd83dbSDimitry Andric       .addReg(ValReg)
387*5ffd83dbSDimitry Andric       .addReg(ShamtReg);
388*5ffd83dbSDimitry Andric }
389*5ffd83dbSDimitry Andric 
390*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicMinMaxOp(
391*5ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
392*5ffd83dbSDimitry Andric     AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
393*5ffd83dbSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
394*5ffd83dbSDimitry Andric   assert(IsMasked == true &&
395*5ffd83dbSDimitry Andric          "Should only need to expand masked atomic max/min");
396*5ffd83dbSDimitry Andric   assert(Width == 32 && "Should never need to expand masked 64-bit operations");
397*5ffd83dbSDimitry Andric 
398*5ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
399*5ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
400*5ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
401*5ffd83dbSDimitry Andric   auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
402*5ffd83dbSDimitry Andric   auto LoopIfBodyMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
403*5ffd83dbSDimitry Andric   auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
404*5ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
405*5ffd83dbSDimitry Andric 
406*5ffd83dbSDimitry Andric   // Insert new MBBs.
407*5ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopHeadMBB);
408*5ffd83dbSDimitry Andric   MF->insert(++LoopHeadMBB->getIterator(), LoopIfBodyMBB);
409*5ffd83dbSDimitry Andric   MF->insert(++LoopIfBodyMBB->getIterator(), LoopTailMBB);
410*5ffd83dbSDimitry Andric   MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
411*5ffd83dbSDimitry Andric 
412*5ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
413*5ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopIfBodyMBB);
414*5ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopTailMBB);
415*5ffd83dbSDimitry Andric   LoopIfBodyMBB->addSuccessor(LoopTailMBB);
416*5ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(LoopHeadMBB);
417*5ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(DoneMBB);
418*5ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
419*5ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
420*5ffd83dbSDimitry Andric   MBB.addSuccessor(LoopHeadMBB);
421*5ffd83dbSDimitry Andric 
422*5ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
423*5ffd83dbSDimitry Andric   Register Scratch1Reg = MI.getOperand(1).getReg();
424*5ffd83dbSDimitry Andric   Register Scratch2Reg = MI.getOperand(2).getReg();
425*5ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(3).getReg();
426*5ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(4).getReg();
427*5ffd83dbSDimitry Andric   Register MaskReg = MI.getOperand(5).getReg();
428*5ffd83dbSDimitry Andric   bool IsSigned = BinOp == AtomicRMWInst::Min || BinOp == AtomicRMWInst::Max;
429*5ffd83dbSDimitry Andric   AtomicOrdering Ordering =
430*5ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(IsSigned ? 7 : 6).getImm());
431*5ffd83dbSDimitry Andric 
432*5ffd83dbSDimitry Andric   //
433*5ffd83dbSDimitry Andric   // .loophead:
434*5ffd83dbSDimitry Andric   //   lr.w destreg, (alignedaddr)
435*5ffd83dbSDimitry Andric   //   and scratch2, destreg, mask
436*5ffd83dbSDimitry Andric   //   mv scratch1, destreg
437*5ffd83dbSDimitry Andric   //   [sext scratch2 if signed min/max]
438*5ffd83dbSDimitry Andric   //   ifnochangeneeded scratch2, incr, .looptail
439*5ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
440*5ffd83dbSDimitry Andric       .addReg(AddrReg);
441*5ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), Scratch2Reg)
442*5ffd83dbSDimitry Andric       .addReg(DestReg)
443*5ffd83dbSDimitry Andric       .addReg(MaskReg);
444*5ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(RISCV::ADDI), Scratch1Reg)
445*5ffd83dbSDimitry Andric       .addReg(DestReg)
446*5ffd83dbSDimitry Andric       .addImm(0);
447*5ffd83dbSDimitry Andric 
448*5ffd83dbSDimitry Andric   switch (BinOp) {
449*5ffd83dbSDimitry Andric   default:
450*5ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
451*5ffd83dbSDimitry Andric   case AtomicRMWInst::Max: {
452*5ffd83dbSDimitry Andric     insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
453*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
454*5ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
455*5ffd83dbSDimitry Andric         .addReg(IncrReg)
456*5ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
457*5ffd83dbSDimitry Andric     break;
458*5ffd83dbSDimitry Andric   }
459*5ffd83dbSDimitry Andric   case AtomicRMWInst::Min: {
460*5ffd83dbSDimitry Andric     insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
461*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
462*5ffd83dbSDimitry Andric         .addReg(IncrReg)
463*5ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
464*5ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
465*5ffd83dbSDimitry Andric     break;
466*5ffd83dbSDimitry Andric   }
467*5ffd83dbSDimitry Andric   case AtomicRMWInst::UMax:
468*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
469*5ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
470*5ffd83dbSDimitry Andric         .addReg(IncrReg)
471*5ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
472*5ffd83dbSDimitry Andric     break;
473*5ffd83dbSDimitry Andric   case AtomicRMWInst::UMin:
474*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
475*5ffd83dbSDimitry Andric         .addReg(IncrReg)
476*5ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
477*5ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
478*5ffd83dbSDimitry Andric     break;
479*5ffd83dbSDimitry Andric   }
480*5ffd83dbSDimitry Andric 
481*5ffd83dbSDimitry Andric   // .loopifbody:
482*5ffd83dbSDimitry Andric   //   xor scratch1, destreg, incr
483*5ffd83dbSDimitry Andric   //   and scratch1, scratch1, mask
484*5ffd83dbSDimitry Andric   //   xor scratch1, destreg, scratch1
485*5ffd83dbSDimitry Andric   insertMaskedMerge(TII, DL, LoopIfBodyMBB, Scratch1Reg, DestReg, IncrReg,
486*5ffd83dbSDimitry Andric                     MaskReg, Scratch1Reg);
487*5ffd83dbSDimitry Andric 
488*5ffd83dbSDimitry Andric   // .looptail:
489*5ffd83dbSDimitry Andric   //   sc.w scratch1, scratch1, (addr)
490*5ffd83dbSDimitry Andric   //   bnez scratch1, loop
491*5ffd83dbSDimitry Andric   BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), Scratch1Reg)
492*5ffd83dbSDimitry Andric       .addReg(AddrReg)
493*5ffd83dbSDimitry Andric       .addReg(Scratch1Reg);
494*5ffd83dbSDimitry Andric   BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
495*5ffd83dbSDimitry Andric       .addReg(Scratch1Reg)
496*5ffd83dbSDimitry Andric       .addReg(RISCV::X0)
497*5ffd83dbSDimitry Andric       .addMBB(LoopHeadMBB);
498*5ffd83dbSDimitry Andric 
499*5ffd83dbSDimitry Andric   NextMBBI = MBB.end();
500*5ffd83dbSDimitry Andric   MI.eraseFromParent();
501*5ffd83dbSDimitry Andric 
502*5ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
503*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
504*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopIfBodyMBB);
505*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
506*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
507*5ffd83dbSDimitry Andric 
508*5ffd83dbSDimitry Andric   return true;
509*5ffd83dbSDimitry Andric }
510*5ffd83dbSDimitry Andric 
511*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicCmpXchg(
512*5ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked,
513*5ffd83dbSDimitry Andric     int Width, MachineBasicBlock::iterator &NextMBBI) {
514*5ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
515*5ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
516*5ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
517*5ffd83dbSDimitry Andric   auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
518*5ffd83dbSDimitry Andric   auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
519*5ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
520*5ffd83dbSDimitry Andric 
521*5ffd83dbSDimitry Andric   // Insert new MBBs.
522*5ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopHeadMBB);
523*5ffd83dbSDimitry Andric   MF->insert(++LoopHeadMBB->getIterator(), LoopTailMBB);
524*5ffd83dbSDimitry Andric   MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
525*5ffd83dbSDimitry Andric 
526*5ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
527*5ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopTailMBB);
528*5ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(DoneMBB);
529*5ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(DoneMBB);
530*5ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(LoopHeadMBB);
531*5ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
532*5ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
533*5ffd83dbSDimitry Andric   MBB.addSuccessor(LoopHeadMBB);
534*5ffd83dbSDimitry Andric 
535*5ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
536*5ffd83dbSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
537*5ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
538*5ffd83dbSDimitry Andric   Register CmpValReg = MI.getOperand(3).getReg();
539*5ffd83dbSDimitry Andric   Register NewValReg = MI.getOperand(4).getReg();
540*5ffd83dbSDimitry Andric   AtomicOrdering Ordering =
541*5ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(IsMasked ? 6 : 5).getImm());
542*5ffd83dbSDimitry Andric 
543*5ffd83dbSDimitry Andric   if (!IsMasked) {
544*5ffd83dbSDimitry Andric     // .loophead:
545*5ffd83dbSDimitry Andric     //   lr.[w|d] dest, (addr)
546*5ffd83dbSDimitry Andric     //   bne dest, cmpval, done
547*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
548*5ffd83dbSDimitry Andric         .addReg(AddrReg);
549*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
550*5ffd83dbSDimitry Andric         .addReg(DestReg)
551*5ffd83dbSDimitry Andric         .addReg(CmpValReg)
552*5ffd83dbSDimitry Andric         .addMBB(DoneMBB);
553*5ffd83dbSDimitry Andric     // .looptail:
554*5ffd83dbSDimitry Andric     //   sc.[w|d] scratch, newval, (addr)
555*5ffd83dbSDimitry Andric     //   bnez scratch, loophead
556*5ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
557*5ffd83dbSDimitry Andric         .addReg(AddrReg)
558*5ffd83dbSDimitry Andric         .addReg(NewValReg);
559*5ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
560*5ffd83dbSDimitry Andric         .addReg(ScratchReg)
561*5ffd83dbSDimitry Andric         .addReg(RISCV::X0)
562*5ffd83dbSDimitry Andric         .addMBB(LoopHeadMBB);
563*5ffd83dbSDimitry Andric   } else {
564*5ffd83dbSDimitry Andric     // .loophead:
565*5ffd83dbSDimitry Andric     //   lr.w dest, (addr)
566*5ffd83dbSDimitry Andric     //   and scratch, dest, mask
567*5ffd83dbSDimitry Andric     //   bne scratch, cmpval, done
568*5ffd83dbSDimitry Andric     Register MaskReg = MI.getOperand(5).getReg();
569*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
570*5ffd83dbSDimitry Andric         .addReg(AddrReg);
571*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), ScratchReg)
572*5ffd83dbSDimitry Andric         .addReg(DestReg)
573*5ffd83dbSDimitry Andric         .addReg(MaskReg);
574*5ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
575*5ffd83dbSDimitry Andric         .addReg(ScratchReg)
576*5ffd83dbSDimitry Andric         .addReg(CmpValReg)
577*5ffd83dbSDimitry Andric         .addMBB(DoneMBB);
578*5ffd83dbSDimitry Andric 
579*5ffd83dbSDimitry Andric     // .looptail:
580*5ffd83dbSDimitry Andric     //   xor scratch, dest, newval
581*5ffd83dbSDimitry Andric     //   and scratch, scratch, mask
582*5ffd83dbSDimitry Andric     //   xor scratch, dest, scratch
583*5ffd83dbSDimitry Andric     //   sc.w scratch, scratch, (adrr)
584*5ffd83dbSDimitry Andric     //   bnez scratch, loophead
585*5ffd83dbSDimitry Andric     insertMaskedMerge(TII, DL, LoopTailMBB, ScratchReg, DestReg, NewValReg,
586*5ffd83dbSDimitry Andric                       MaskReg, ScratchReg);
587*5ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
588*5ffd83dbSDimitry Andric         .addReg(AddrReg)
589*5ffd83dbSDimitry Andric         .addReg(ScratchReg);
590*5ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
591*5ffd83dbSDimitry Andric         .addReg(ScratchReg)
592*5ffd83dbSDimitry Andric         .addReg(RISCV::X0)
593*5ffd83dbSDimitry Andric         .addMBB(LoopHeadMBB);
594*5ffd83dbSDimitry Andric   }
595*5ffd83dbSDimitry Andric 
596*5ffd83dbSDimitry Andric   NextMBBI = MBB.end();
597*5ffd83dbSDimitry Andric   MI.eraseFromParent();
598*5ffd83dbSDimitry Andric 
599*5ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
600*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
601*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
602*5ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
603*5ffd83dbSDimitry Andric 
604*5ffd83dbSDimitry Andric   return true;
605*5ffd83dbSDimitry Andric }
606*5ffd83dbSDimitry Andric 
607*5ffd83dbSDimitry Andric } // end of anonymous namespace
608*5ffd83dbSDimitry Andric 
609*5ffd83dbSDimitry Andric INITIALIZE_PASS(RISCVExpandAtomicPseudo, "riscv-expand-atomic-pseudo",
610*5ffd83dbSDimitry Andric                 RISCV_EXPAND_ATOMIC_PSEUDO_NAME, false, false)
611*5ffd83dbSDimitry Andric 
612*5ffd83dbSDimitry Andric namespace llvm {
613*5ffd83dbSDimitry Andric 
614*5ffd83dbSDimitry Andric FunctionPass *createRISCVExpandAtomicPseudoPass() {
615*5ffd83dbSDimitry Andric   return new RISCVExpandAtomicPseudo();
616*5ffd83dbSDimitry Andric }
617*5ffd83dbSDimitry Andric 
618*5ffd83dbSDimitry Andric } // end of namespace llvm
619