xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVExpandAtomicPseudoInsts.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //===-- RISCVExpandAtomicPseudoInsts.cpp - Expand atomic pseudo instrs. ---===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // This file contains a pass that expands atomic pseudo instructions into
105ffd83dbSDimitry Andric // target instructions. This pass should be run at the last possible moment,
115ffd83dbSDimitry Andric // avoiding the possibility for other passes to break the requirements for
125ffd83dbSDimitry Andric // forward progress in the LR/SC block.
135ffd83dbSDimitry Andric //
145ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
155ffd83dbSDimitry Andric 
165ffd83dbSDimitry Andric #include "RISCV.h"
175ffd83dbSDimitry Andric #include "RISCVInstrInfo.h"
185ffd83dbSDimitry Andric #include "RISCVTargetMachine.h"
195ffd83dbSDimitry Andric 
205ffd83dbSDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
215ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
225ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
235ffd83dbSDimitry Andric 
245ffd83dbSDimitry Andric using namespace llvm;
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric #define RISCV_EXPAND_ATOMIC_PSEUDO_NAME                                        \
2706c3fb27SDimitry Andric   "RISC-V atomic pseudo instruction expansion pass"
285ffd83dbSDimitry Andric 
295ffd83dbSDimitry Andric namespace {
305ffd83dbSDimitry Andric 
315ffd83dbSDimitry Andric class RISCVExpandAtomicPseudo : public MachineFunctionPass {
325ffd83dbSDimitry Andric public:
33*5f757f3fSDimitry Andric   const RISCVSubtarget *STI;
345ffd83dbSDimitry Andric   const RISCVInstrInfo *TII;
355ffd83dbSDimitry Andric   static char ID;
365ffd83dbSDimitry Andric 
375ffd83dbSDimitry Andric   RISCVExpandAtomicPseudo() : MachineFunctionPass(ID) {
385ffd83dbSDimitry Andric     initializeRISCVExpandAtomicPseudoPass(*PassRegistry::getPassRegistry());
395ffd83dbSDimitry Andric   }
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
425ffd83dbSDimitry Andric 
435ffd83dbSDimitry Andric   StringRef getPassName() const override {
445ffd83dbSDimitry Andric     return RISCV_EXPAND_ATOMIC_PSEUDO_NAME;
455ffd83dbSDimitry Andric   }
465ffd83dbSDimitry Andric 
475ffd83dbSDimitry Andric private:
485ffd83dbSDimitry Andric   bool expandMBB(MachineBasicBlock &MBB);
495ffd83dbSDimitry Andric   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
505ffd83dbSDimitry Andric                 MachineBasicBlock::iterator &NextMBBI);
515ffd83dbSDimitry Andric   bool expandAtomicBinOp(MachineBasicBlock &MBB,
525ffd83dbSDimitry Andric                          MachineBasicBlock::iterator MBBI, AtomicRMWInst::BinOp,
535ffd83dbSDimitry Andric                          bool IsMasked, int Width,
545ffd83dbSDimitry Andric                          MachineBasicBlock::iterator &NextMBBI);
555ffd83dbSDimitry Andric   bool expandAtomicMinMaxOp(MachineBasicBlock &MBB,
565ffd83dbSDimitry Andric                             MachineBasicBlock::iterator MBBI,
575ffd83dbSDimitry Andric                             AtomicRMWInst::BinOp, bool IsMasked, int Width,
585ffd83dbSDimitry Andric                             MachineBasicBlock::iterator &NextMBBI);
595ffd83dbSDimitry Andric   bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
605ffd83dbSDimitry Andric                            MachineBasicBlock::iterator MBBI, bool IsMasked,
615ffd83dbSDimitry Andric                            int Width, MachineBasicBlock::iterator &NextMBBI);
6206c3fb27SDimitry Andric #ifndef NDEBUG
6306c3fb27SDimitry Andric   unsigned getInstSizeInBytes(const MachineFunction &MF) const {
6406c3fb27SDimitry Andric     unsigned Size = 0;
6506c3fb27SDimitry Andric     for (auto &MBB : MF)
6606c3fb27SDimitry Andric       for (auto &MI : MBB)
6706c3fb27SDimitry Andric         Size += TII->getInstSizeInBytes(MI);
6806c3fb27SDimitry Andric     return Size;
6906c3fb27SDimitry Andric   }
7006c3fb27SDimitry Andric #endif
715ffd83dbSDimitry Andric };
725ffd83dbSDimitry Andric 
735ffd83dbSDimitry Andric char RISCVExpandAtomicPseudo::ID = 0;
745ffd83dbSDimitry Andric 
755ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::runOnMachineFunction(MachineFunction &MF) {
76*5f757f3fSDimitry Andric   STI = &MF.getSubtarget<RISCVSubtarget>();
77*5f757f3fSDimitry Andric   TII = STI->getInstrInfo();
7806c3fb27SDimitry Andric 
7906c3fb27SDimitry Andric #ifndef NDEBUG
8006c3fb27SDimitry Andric   const unsigned OldSize = getInstSizeInBytes(MF);
8106c3fb27SDimitry Andric #endif
8206c3fb27SDimitry Andric 
835ffd83dbSDimitry Andric   bool Modified = false;
845ffd83dbSDimitry Andric   for (auto &MBB : MF)
855ffd83dbSDimitry Andric     Modified |= expandMBB(MBB);
8606c3fb27SDimitry Andric 
8706c3fb27SDimitry Andric #ifndef NDEBUG
8806c3fb27SDimitry Andric   const unsigned NewSize = getInstSizeInBytes(MF);
8906c3fb27SDimitry Andric   assert(OldSize >= NewSize);
9006c3fb27SDimitry Andric #endif
915ffd83dbSDimitry Andric   return Modified;
925ffd83dbSDimitry Andric }
935ffd83dbSDimitry Andric 
945ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMBB(MachineBasicBlock &MBB) {
955ffd83dbSDimitry Andric   bool Modified = false;
965ffd83dbSDimitry Andric 
975ffd83dbSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
985ffd83dbSDimitry Andric   while (MBBI != E) {
995ffd83dbSDimitry Andric     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
1005ffd83dbSDimitry Andric     Modified |= expandMI(MBB, MBBI, NMBBI);
1015ffd83dbSDimitry Andric     MBBI = NMBBI;
1025ffd83dbSDimitry Andric   }
1035ffd83dbSDimitry Andric 
1045ffd83dbSDimitry Andric   return Modified;
1055ffd83dbSDimitry Andric }
1065ffd83dbSDimitry Andric 
1075ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMI(MachineBasicBlock &MBB,
1085ffd83dbSDimitry Andric                                        MachineBasicBlock::iterator MBBI,
1095ffd83dbSDimitry Andric                                        MachineBasicBlock::iterator &NextMBBI) {
1101fd87a68SDimitry Andric   // RISCVInstrInfo::getInstSizeInBytes expects that the total size of the
1111fd87a68SDimitry Andric   // expanded instructions for each pseudo is correct in the Size field of the
1121fd87a68SDimitry Andric   // tablegen definition for the pseudo.
1135ffd83dbSDimitry Andric   switch (MBBI->getOpcode()) {
1145ffd83dbSDimitry Andric   case RISCV::PseudoAtomicLoadNand32:
1155ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 32,
1165ffd83dbSDimitry Andric                              NextMBBI);
1175ffd83dbSDimitry Andric   case RISCV::PseudoAtomicLoadNand64:
1185ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 64,
1195ffd83dbSDimitry Andric                              NextMBBI);
1205ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicSwap32:
1215ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, true, 32,
1225ffd83dbSDimitry Andric                              NextMBBI);
1235ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadAdd32:
1245ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Add, true, 32, NextMBBI);
1255ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadSub32:
1265ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Sub, true, 32, NextMBBI);
1275ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadNand32:
1285ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, true, 32,
1295ffd83dbSDimitry Andric                              NextMBBI);
1305ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadMax32:
1315ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Max, true, 32,
1325ffd83dbSDimitry Andric                                 NextMBBI);
1335ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadMin32:
1345ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Min, true, 32,
1355ffd83dbSDimitry Andric                                 NextMBBI);
1365ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadUMax32:
1375ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMax, true, 32,
1385ffd83dbSDimitry Andric                                 NextMBBI);
1395ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadUMin32:
1405ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, true, 32,
1415ffd83dbSDimitry Andric                                 NextMBBI);
1425ffd83dbSDimitry Andric   case RISCV::PseudoCmpXchg32:
1435ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, false, 32, NextMBBI);
1445ffd83dbSDimitry Andric   case RISCV::PseudoCmpXchg64:
1455ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
1465ffd83dbSDimitry Andric   case RISCV::PseudoMaskedCmpXchg32:
1475ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
1485ffd83dbSDimitry Andric   }
1495ffd83dbSDimitry Andric 
1505ffd83dbSDimitry Andric   return false;
1515ffd83dbSDimitry Andric }
1525ffd83dbSDimitry Andric 
153*5f757f3fSDimitry Andric static unsigned getLRForRMW32(AtomicOrdering Ordering,
154*5f757f3fSDimitry Andric                               const RISCVSubtarget *Subtarget) {
1555ffd83dbSDimitry Andric   switch (Ordering) {
1565ffd83dbSDimitry Andric   default:
1575ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
1585ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
1595ffd83dbSDimitry Andric     return RISCV::LR_W;
1605ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
161*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
162*5f757f3fSDimitry Andric       return RISCV::LR_W;
1635ffd83dbSDimitry Andric     return RISCV::LR_W_AQ;
1645ffd83dbSDimitry Andric   case AtomicOrdering::Release:
1655ffd83dbSDimitry Andric     return RISCV::LR_W;
1665ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
167*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
168*5f757f3fSDimitry Andric       return RISCV::LR_W;
1695ffd83dbSDimitry Andric     return RISCV::LR_W_AQ;
1705ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
1715ffd83dbSDimitry Andric     return RISCV::LR_W_AQ_RL;
1725ffd83dbSDimitry Andric   }
1735ffd83dbSDimitry Andric }
1745ffd83dbSDimitry Andric 
175*5f757f3fSDimitry Andric static unsigned getSCForRMW32(AtomicOrdering Ordering,
176*5f757f3fSDimitry Andric                               const RISCVSubtarget *Subtarget) {
1775ffd83dbSDimitry Andric   switch (Ordering) {
1785ffd83dbSDimitry Andric   default:
1795ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
1805ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
1815ffd83dbSDimitry Andric     return RISCV::SC_W;
1825ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
1835ffd83dbSDimitry Andric     return RISCV::SC_W;
1845ffd83dbSDimitry Andric   case AtomicOrdering::Release:
185*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
186*5f757f3fSDimitry Andric       return RISCV::SC_W;
1875ffd83dbSDimitry Andric     return RISCV::SC_W_RL;
1885ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
189*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
190*5f757f3fSDimitry Andric       return RISCV::SC_W;
1915ffd83dbSDimitry Andric     return RISCV::SC_W_RL;
1925ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
19306c3fb27SDimitry Andric     return RISCV::SC_W_RL;
1945ffd83dbSDimitry Andric   }
1955ffd83dbSDimitry Andric }
1965ffd83dbSDimitry Andric 
197*5f757f3fSDimitry Andric static unsigned getLRForRMW64(AtomicOrdering Ordering,
198*5f757f3fSDimitry Andric                               const RISCVSubtarget *Subtarget) {
1995ffd83dbSDimitry Andric   switch (Ordering) {
2005ffd83dbSDimitry Andric   default:
2015ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
2025ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
2035ffd83dbSDimitry Andric     return RISCV::LR_D;
2045ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
205*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
206*5f757f3fSDimitry Andric       return RISCV::LR_D;
2075ffd83dbSDimitry Andric     return RISCV::LR_D_AQ;
2085ffd83dbSDimitry Andric   case AtomicOrdering::Release:
2095ffd83dbSDimitry Andric     return RISCV::LR_D;
2105ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
211*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
212*5f757f3fSDimitry Andric       return RISCV::LR_D;
2135ffd83dbSDimitry Andric     return RISCV::LR_D_AQ;
2145ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
2155ffd83dbSDimitry Andric     return RISCV::LR_D_AQ_RL;
2165ffd83dbSDimitry Andric   }
2175ffd83dbSDimitry Andric }
2185ffd83dbSDimitry Andric 
219*5f757f3fSDimitry Andric static unsigned getSCForRMW64(AtomicOrdering Ordering,
220*5f757f3fSDimitry Andric                               const RISCVSubtarget *Subtarget) {
2215ffd83dbSDimitry Andric   switch (Ordering) {
2225ffd83dbSDimitry Andric   default:
2235ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
2245ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
2255ffd83dbSDimitry Andric     return RISCV::SC_D;
2265ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
2275ffd83dbSDimitry Andric     return RISCV::SC_D;
2285ffd83dbSDimitry Andric   case AtomicOrdering::Release:
229*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
230*5f757f3fSDimitry Andric       return RISCV::SC_D;
2315ffd83dbSDimitry Andric     return RISCV::SC_D_RL;
2325ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
233*5f757f3fSDimitry Andric     if (Subtarget->hasStdExtZtso())
234*5f757f3fSDimitry Andric       return RISCV::SC_D;
2355ffd83dbSDimitry Andric     return RISCV::SC_D_RL;
2365ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
23706c3fb27SDimitry Andric     return RISCV::SC_D_RL;
2385ffd83dbSDimitry Andric   }
2395ffd83dbSDimitry Andric }
2405ffd83dbSDimitry Andric 
241*5f757f3fSDimitry Andric static unsigned getLRForRMW(AtomicOrdering Ordering, int Width,
242*5f757f3fSDimitry Andric                             const RISCVSubtarget *Subtarget) {
2435ffd83dbSDimitry Andric   if (Width == 32)
244*5f757f3fSDimitry Andric     return getLRForRMW32(Ordering, Subtarget);
2455ffd83dbSDimitry Andric   if (Width == 64)
246*5f757f3fSDimitry Andric     return getLRForRMW64(Ordering, Subtarget);
2475ffd83dbSDimitry Andric   llvm_unreachable("Unexpected LR width\n");
2485ffd83dbSDimitry Andric }
2495ffd83dbSDimitry Andric 
250*5f757f3fSDimitry Andric static unsigned getSCForRMW(AtomicOrdering Ordering, int Width,
251*5f757f3fSDimitry Andric                             const RISCVSubtarget *Subtarget) {
2525ffd83dbSDimitry Andric   if (Width == 32)
253*5f757f3fSDimitry Andric     return getSCForRMW32(Ordering, Subtarget);
2545ffd83dbSDimitry Andric   if (Width == 64)
255*5f757f3fSDimitry Andric     return getSCForRMW64(Ordering, Subtarget);
2565ffd83dbSDimitry Andric   llvm_unreachable("Unexpected SC width\n");
2575ffd83dbSDimitry Andric }
2585ffd83dbSDimitry Andric 
2595ffd83dbSDimitry Andric static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI,
2605ffd83dbSDimitry Andric                                    DebugLoc DL, MachineBasicBlock *ThisMBB,
2615ffd83dbSDimitry Andric                                    MachineBasicBlock *LoopMBB,
2625ffd83dbSDimitry Andric                                    MachineBasicBlock *DoneMBB,
263*5f757f3fSDimitry Andric                                    AtomicRMWInst::BinOp BinOp, int Width,
264*5f757f3fSDimitry Andric                                    const RISCVSubtarget *STI) {
2655ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
2665ffd83dbSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
2675ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
2685ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(3).getReg();
2695ffd83dbSDimitry Andric   AtomicOrdering Ordering =
2705ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(4).getImm());
2715ffd83dbSDimitry Andric 
2725ffd83dbSDimitry Andric   // .loop:
2735ffd83dbSDimitry Andric   //   lr.[w|d] dest, (addr)
2745ffd83dbSDimitry Andric   //   binop scratch, dest, val
2755ffd83dbSDimitry Andric   //   sc.[w|d] scratch, scratch, (addr)
2765ffd83dbSDimitry Andric   //   bnez scratch, loop
277*5f757f3fSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getLRForRMW(Ordering, Width, STI)), DestReg)
2785ffd83dbSDimitry Andric       .addReg(AddrReg);
2795ffd83dbSDimitry Andric   switch (BinOp) {
2805ffd83dbSDimitry Andric   default:
2815ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
2825ffd83dbSDimitry Andric   case AtomicRMWInst::Nand:
2835ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
2845ffd83dbSDimitry Andric         .addReg(DestReg)
2855ffd83dbSDimitry Andric         .addReg(IncrReg);
2865ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
2875ffd83dbSDimitry Andric         .addReg(ScratchReg)
2885ffd83dbSDimitry Andric         .addImm(-1);
2895ffd83dbSDimitry Andric     break;
2905ffd83dbSDimitry Andric   }
291*5f757f3fSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getSCForRMW(Ordering, Width, STI)), ScratchReg)
2925ffd83dbSDimitry Andric       .addReg(AddrReg)
2935ffd83dbSDimitry Andric       .addReg(ScratchReg);
2945ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
2955ffd83dbSDimitry Andric       .addReg(ScratchReg)
2965ffd83dbSDimitry Andric       .addReg(RISCV::X0)
2975ffd83dbSDimitry Andric       .addMBB(LoopMBB);
2985ffd83dbSDimitry Andric }
2995ffd83dbSDimitry Andric 
3005ffd83dbSDimitry Andric static void insertMaskedMerge(const RISCVInstrInfo *TII, DebugLoc DL,
3015ffd83dbSDimitry Andric                               MachineBasicBlock *MBB, Register DestReg,
3025ffd83dbSDimitry Andric                               Register OldValReg, Register NewValReg,
3035ffd83dbSDimitry Andric                               Register MaskReg, Register ScratchReg) {
3045ffd83dbSDimitry Andric   assert(OldValReg != ScratchReg && "OldValReg and ScratchReg must be unique");
3055ffd83dbSDimitry Andric   assert(OldValReg != MaskReg && "OldValReg and MaskReg must be unique");
3065ffd83dbSDimitry Andric   assert(ScratchReg != MaskReg && "ScratchReg and MaskReg must be unique");
3075ffd83dbSDimitry Andric 
3085ffd83dbSDimitry Andric   // We select bits from newval and oldval using:
3095ffd83dbSDimitry Andric   // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
3105ffd83dbSDimitry Andric   // r = oldval ^ ((oldval ^ newval) & masktargetdata);
3115ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::XOR), ScratchReg)
3125ffd83dbSDimitry Andric       .addReg(OldValReg)
3135ffd83dbSDimitry Andric       .addReg(NewValReg);
3145ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::AND), ScratchReg)
3155ffd83dbSDimitry Andric       .addReg(ScratchReg)
3165ffd83dbSDimitry Andric       .addReg(MaskReg);
3175ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::XOR), DestReg)
3185ffd83dbSDimitry Andric       .addReg(OldValReg)
3195ffd83dbSDimitry Andric       .addReg(ScratchReg);
3205ffd83dbSDimitry Andric }
3215ffd83dbSDimitry Andric 
322*5f757f3fSDimitry Andric static void doMaskedAtomicBinOpExpansion(const RISCVInstrInfo *TII,
323*5f757f3fSDimitry Andric                                          MachineInstr &MI, DebugLoc DL,
324*5f757f3fSDimitry Andric                                          MachineBasicBlock *ThisMBB,
325*5f757f3fSDimitry Andric                                          MachineBasicBlock *LoopMBB,
326*5f757f3fSDimitry Andric                                          MachineBasicBlock *DoneMBB,
327*5f757f3fSDimitry Andric                                          AtomicRMWInst::BinOp BinOp, int Width,
328*5f757f3fSDimitry Andric                                          const RISCVSubtarget *STI) {
3295ffd83dbSDimitry Andric   assert(Width == 32 && "Should never need to expand masked 64-bit operations");
3305ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
3315ffd83dbSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
3325ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
3335ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(3).getReg();
3345ffd83dbSDimitry Andric   Register MaskReg = MI.getOperand(4).getReg();
3355ffd83dbSDimitry Andric   AtomicOrdering Ordering =
3365ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(5).getImm());
3375ffd83dbSDimitry Andric 
3385ffd83dbSDimitry Andric   // .loop:
3395ffd83dbSDimitry Andric   //   lr.w destreg, (alignedaddr)
3405ffd83dbSDimitry Andric   //   binop scratch, destreg, incr
3415ffd83dbSDimitry Andric   //   xor scratch, destreg, scratch
3425ffd83dbSDimitry Andric   //   and scratch, scratch, masktargetdata
3435ffd83dbSDimitry Andric   //   xor scratch, destreg, scratch
3445ffd83dbSDimitry Andric   //   sc.w scratch, scratch, (alignedaddr)
3455ffd83dbSDimitry Andric   //   bnez scratch, loop
346*5f757f3fSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getLRForRMW32(Ordering, STI)), DestReg)
3475ffd83dbSDimitry Andric       .addReg(AddrReg);
3485ffd83dbSDimitry Andric   switch (BinOp) {
3495ffd83dbSDimitry Andric   default:
3505ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
3515ffd83dbSDimitry Andric   case AtomicRMWInst::Xchg:
3525ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::ADDI), ScratchReg)
3535ffd83dbSDimitry Andric         .addReg(IncrReg)
3545ffd83dbSDimitry Andric         .addImm(0);
3555ffd83dbSDimitry Andric     break;
3565ffd83dbSDimitry Andric   case AtomicRMWInst::Add:
3575ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg)
3585ffd83dbSDimitry Andric         .addReg(DestReg)
3595ffd83dbSDimitry Andric         .addReg(IncrReg);
3605ffd83dbSDimitry Andric     break;
3615ffd83dbSDimitry Andric   case AtomicRMWInst::Sub:
3625ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::SUB), ScratchReg)
3635ffd83dbSDimitry Andric         .addReg(DestReg)
3645ffd83dbSDimitry Andric         .addReg(IncrReg);
3655ffd83dbSDimitry Andric     break;
3665ffd83dbSDimitry Andric   case AtomicRMWInst::Nand:
3675ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
3685ffd83dbSDimitry Andric         .addReg(DestReg)
3695ffd83dbSDimitry Andric         .addReg(IncrReg);
3705ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
3715ffd83dbSDimitry Andric         .addReg(ScratchReg)
3725ffd83dbSDimitry Andric         .addImm(-1);
3735ffd83dbSDimitry Andric     break;
3745ffd83dbSDimitry Andric   }
3755ffd83dbSDimitry Andric 
3765ffd83dbSDimitry Andric   insertMaskedMerge(TII, DL, LoopMBB, ScratchReg, DestReg, ScratchReg, MaskReg,
3775ffd83dbSDimitry Andric                     ScratchReg);
3785ffd83dbSDimitry Andric 
379*5f757f3fSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getSCForRMW32(Ordering, STI)), ScratchReg)
3805ffd83dbSDimitry Andric       .addReg(AddrReg)
3815ffd83dbSDimitry Andric       .addReg(ScratchReg);
3825ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
3835ffd83dbSDimitry Andric       .addReg(ScratchReg)
3845ffd83dbSDimitry Andric       .addReg(RISCV::X0)
3855ffd83dbSDimitry Andric       .addMBB(LoopMBB);
3865ffd83dbSDimitry Andric }
3875ffd83dbSDimitry Andric 
3885ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicBinOp(
3895ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
3905ffd83dbSDimitry Andric     AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
3915ffd83dbSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
3925ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
3935ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
3945ffd83dbSDimitry Andric 
3955ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
3965ffd83dbSDimitry Andric   auto LoopMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
3975ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
3985ffd83dbSDimitry Andric 
3995ffd83dbSDimitry Andric   // Insert new MBBs.
4005ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopMBB);
4015ffd83dbSDimitry Andric   MF->insert(++LoopMBB->getIterator(), DoneMBB);
4025ffd83dbSDimitry Andric 
4035ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
4045ffd83dbSDimitry Andric   LoopMBB->addSuccessor(LoopMBB);
4055ffd83dbSDimitry Andric   LoopMBB->addSuccessor(DoneMBB);
4065ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
4075ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
4085ffd83dbSDimitry Andric   MBB.addSuccessor(LoopMBB);
4095ffd83dbSDimitry Andric 
4105ffd83dbSDimitry Andric   if (!IsMasked)
411*5f757f3fSDimitry Andric     doAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp, Width,
412*5f757f3fSDimitry Andric                            STI);
4135ffd83dbSDimitry Andric   else
4145ffd83dbSDimitry Andric     doMaskedAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp,
415*5f757f3fSDimitry Andric                                  Width, STI);
4165ffd83dbSDimitry Andric 
4175ffd83dbSDimitry Andric   NextMBBI = MBB.end();
4185ffd83dbSDimitry Andric   MI.eraseFromParent();
4195ffd83dbSDimitry Andric 
4205ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
4215ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopMBB);
4225ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
4235ffd83dbSDimitry Andric 
4245ffd83dbSDimitry Andric   return true;
4255ffd83dbSDimitry Andric }
4265ffd83dbSDimitry Andric 
4275ffd83dbSDimitry Andric static void insertSext(const RISCVInstrInfo *TII, DebugLoc DL,
4285ffd83dbSDimitry Andric                        MachineBasicBlock *MBB, Register ValReg,
4295ffd83dbSDimitry Andric                        Register ShamtReg) {
4305ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::SLL), ValReg)
4315ffd83dbSDimitry Andric       .addReg(ValReg)
4325ffd83dbSDimitry Andric       .addReg(ShamtReg);
4335ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::SRA), ValReg)
4345ffd83dbSDimitry Andric       .addReg(ValReg)
4355ffd83dbSDimitry Andric       .addReg(ShamtReg);
4365ffd83dbSDimitry Andric }
4375ffd83dbSDimitry Andric 
4385ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicMinMaxOp(
4395ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
4405ffd83dbSDimitry Andric     AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
4415ffd83dbSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
4425ffd83dbSDimitry Andric   assert(IsMasked == true &&
4435ffd83dbSDimitry Andric          "Should only need to expand masked atomic max/min");
4445ffd83dbSDimitry Andric   assert(Width == 32 && "Should never need to expand masked 64-bit operations");
4455ffd83dbSDimitry Andric 
4465ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
4475ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
4485ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
4495ffd83dbSDimitry Andric   auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4505ffd83dbSDimitry Andric   auto LoopIfBodyMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4515ffd83dbSDimitry Andric   auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4525ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4535ffd83dbSDimitry Andric 
4545ffd83dbSDimitry Andric   // Insert new MBBs.
4555ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopHeadMBB);
4565ffd83dbSDimitry Andric   MF->insert(++LoopHeadMBB->getIterator(), LoopIfBodyMBB);
4575ffd83dbSDimitry Andric   MF->insert(++LoopIfBodyMBB->getIterator(), LoopTailMBB);
4585ffd83dbSDimitry Andric   MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
4595ffd83dbSDimitry Andric 
4605ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
4615ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopIfBodyMBB);
4625ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopTailMBB);
4635ffd83dbSDimitry Andric   LoopIfBodyMBB->addSuccessor(LoopTailMBB);
4645ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(LoopHeadMBB);
4655ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(DoneMBB);
4665ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
4675ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
4685ffd83dbSDimitry Andric   MBB.addSuccessor(LoopHeadMBB);
4695ffd83dbSDimitry Andric 
4705ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
4715ffd83dbSDimitry Andric   Register Scratch1Reg = MI.getOperand(1).getReg();
4725ffd83dbSDimitry Andric   Register Scratch2Reg = MI.getOperand(2).getReg();
4735ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(3).getReg();
4745ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(4).getReg();
4755ffd83dbSDimitry Andric   Register MaskReg = MI.getOperand(5).getReg();
4765ffd83dbSDimitry Andric   bool IsSigned = BinOp == AtomicRMWInst::Min || BinOp == AtomicRMWInst::Max;
4775ffd83dbSDimitry Andric   AtomicOrdering Ordering =
4785ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(IsSigned ? 7 : 6).getImm());
4795ffd83dbSDimitry Andric 
4805ffd83dbSDimitry Andric   //
4815ffd83dbSDimitry Andric   // .loophead:
4825ffd83dbSDimitry Andric   //   lr.w destreg, (alignedaddr)
4835ffd83dbSDimitry Andric   //   and scratch2, destreg, mask
4845ffd83dbSDimitry Andric   //   mv scratch1, destreg
4855ffd83dbSDimitry Andric   //   [sext scratch2 if signed min/max]
4865ffd83dbSDimitry Andric   //   ifnochangeneeded scratch2, incr, .looptail
487*5f757f3fSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering, STI)), DestReg)
4885ffd83dbSDimitry Andric       .addReg(AddrReg);
4895ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), Scratch2Reg)
4905ffd83dbSDimitry Andric       .addReg(DestReg)
4915ffd83dbSDimitry Andric       .addReg(MaskReg);
4925ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(RISCV::ADDI), Scratch1Reg)
4935ffd83dbSDimitry Andric       .addReg(DestReg)
4945ffd83dbSDimitry Andric       .addImm(0);
4955ffd83dbSDimitry Andric 
4965ffd83dbSDimitry Andric   switch (BinOp) {
4975ffd83dbSDimitry Andric   default:
4985ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
4995ffd83dbSDimitry Andric   case AtomicRMWInst::Max: {
5005ffd83dbSDimitry Andric     insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
5015ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
5025ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
5035ffd83dbSDimitry Andric         .addReg(IncrReg)
5045ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
5055ffd83dbSDimitry Andric     break;
5065ffd83dbSDimitry Andric   }
5075ffd83dbSDimitry Andric   case AtomicRMWInst::Min: {
5085ffd83dbSDimitry Andric     insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
5095ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
5105ffd83dbSDimitry Andric         .addReg(IncrReg)
5115ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
5125ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
5135ffd83dbSDimitry Andric     break;
5145ffd83dbSDimitry Andric   }
5155ffd83dbSDimitry Andric   case AtomicRMWInst::UMax:
5165ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
5175ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
5185ffd83dbSDimitry Andric         .addReg(IncrReg)
5195ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
5205ffd83dbSDimitry Andric     break;
5215ffd83dbSDimitry Andric   case AtomicRMWInst::UMin:
5225ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
5235ffd83dbSDimitry Andric         .addReg(IncrReg)
5245ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
5255ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
5265ffd83dbSDimitry Andric     break;
5275ffd83dbSDimitry Andric   }
5285ffd83dbSDimitry Andric 
5295ffd83dbSDimitry Andric   // .loopifbody:
5305ffd83dbSDimitry Andric   //   xor scratch1, destreg, incr
5315ffd83dbSDimitry Andric   //   and scratch1, scratch1, mask
5325ffd83dbSDimitry Andric   //   xor scratch1, destreg, scratch1
5335ffd83dbSDimitry Andric   insertMaskedMerge(TII, DL, LoopIfBodyMBB, Scratch1Reg, DestReg, IncrReg,
5345ffd83dbSDimitry Andric                     MaskReg, Scratch1Reg);
5355ffd83dbSDimitry Andric 
5365ffd83dbSDimitry Andric   // .looptail:
5375ffd83dbSDimitry Andric   //   sc.w scratch1, scratch1, (addr)
5385ffd83dbSDimitry Andric   //   bnez scratch1, loop
539*5f757f3fSDimitry Andric   BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering, STI)), Scratch1Reg)
5405ffd83dbSDimitry Andric       .addReg(AddrReg)
5415ffd83dbSDimitry Andric       .addReg(Scratch1Reg);
5425ffd83dbSDimitry Andric   BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
5435ffd83dbSDimitry Andric       .addReg(Scratch1Reg)
5445ffd83dbSDimitry Andric       .addReg(RISCV::X0)
5455ffd83dbSDimitry Andric       .addMBB(LoopHeadMBB);
5465ffd83dbSDimitry Andric 
5475ffd83dbSDimitry Andric   NextMBBI = MBB.end();
5485ffd83dbSDimitry Andric   MI.eraseFromParent();
5495ffd83dbSDimitry Andric 
5505ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
5515ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
5525ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopIfBodyMBB);
5535ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
5545ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
5555ffd83dbSDimitry Andric 
5565ffd83dbSDimitry Andric   return true;
5575ffd83dbSDimitry Andric }
5585ffd83dbSDimitry Andric 
559bdd1243dSDimitry Andric // If a BNE on the cmpxchg comparison result immediately follows the cmpxchg
560bdd1243dSDimitry Andric // operation, it can be folded into the cmpxchg expansion by
561bdd1243dSDimitry Andric // modifying the branch within 'LoopHead' (which performs the same
562bdd1243dSDimitry Andric // comparison). This is a valid transformation because after altering the
563bdd1243dSDimitry Andric // LoopHead's BNE destination, the BNE following the cmpxchg becomes
564bdd1243dSDimitry Andric // redundant and and be deleted. In the case of a masked cmpxchg, an
565bdd1243dSDimitry Andric // appropriate AND and BNE must be matched.
566bdd1243dSDimitry Andric //
567bdd1243dSDimitry Andric // On success, returns true and deletes the matching BNE or AND+BNE, sets the
568bdd1243dSDimitry Andric // LoopHeadBNETarget argument to the target that should be used within the
569bdd1243dSDimitry Andric // loop head, and removes that block as a successor to MBB.
570bdd1243dSDimitry Andric bool tryToFoldBNEOnCmpXchgResult(MachineBasicBlock &MBB,
571bdd1243dSDimitry Andric                                  MachineBasicBlock::iterator MBBI,
572bdd1243dSDimitry Andric                                  Register DestReg, Register CmpValReg,
573bdd1243dSDimitry Andric                                  Register MaskReg,
574bdd1243dSDimitry Andric                                  MachineBasicBlock *&LoopHeadBNETarget) {
575bdd1243dSDimitry Andric   SmallVector<MachineInstr *> ToErase;
576bdd1243dSDimitry Andric   auto E = MBB.end();
577bdd1243dSDimitry Andric   if (MBBI == E)
578bdd1243dSDimitry Andric     return false;
579bdd1243dSDimitry Andric   MBBI = skipDebugInstructionsForward(MBBI, E);
580bdd1243dSDimitry Andric 
581bdd1243dSDimitry Andric   // If we have a masked cmpxchg, match AND dst, DestReg, MaskReg.
582bdd1243dSDimitry Andric   if (MaskReg.isValid()) {
583bdd1243dSDimitry Andric     if (MBBI == E || MBBI->getOpcode() != RISCV::AND)
584bdd1243dSDimitry Andric       return false;
585bdd1243dSDimitry Andric     Register ANDOp1 = MBBI->getOperand(1).getReg();
586bdd1243dSDimitry Andric     Register ANDOp2 = MBBI->getOperand(2).getReg();
587bdd1243dSDimitry Andric     if (!(ANDOp1 == DestReg && ANDOp2 == MaskReg) &&
588bdd1243dSDimitry Andric         !(ANDOp1 == MaskReg && ANDOp2 == DestReg))
589bdd1243dSDimitry Andric       return false;
590bdd1243dSDimitry Andric     // We now expect the BNE to use the result of the AND as an operand.
591bdd1243dSDimitry Andric     DestReg = MBBI->getOperand(0).getReg();
592bdd1243dSDimitry Andric     ToErase.push_back(&*MBBI);
593bdd1243dSDimitry Andric     MBBI = skipDebugInstructionsForward(std::next(MBBI), E);
594bdd1243dSDimitry Andric   }
595bdd1243dSDimitry Andric 
596bdd1243dSDimitry Andric   // Match BNE DestReg, MaskReg.
597bdd1243dSDimitry Andric   if (MBBI == E || MBBI->getOpcode() != RISCV::BNE)
598bdd1243dSDimitry Andric     return false;
599bdd1243dSDimitry Andric   Register BNEOp0 = MBBI->getOperand(0).getReg();
600bdd1243dSDimitry Andric   Register BNEOp1 = MBBI->getOperand(1).getReg();
601bdd1243dSDimitry Andric   if (!(BNEOp0 == DestReg && BNEOp1 == CmpValReg) &&
602bdd1243dSDimitry Andric       !(BNEOp0 == CmpValReg && BNEOp1 == DestReg))
603bdd1243dSDimitry Andric     return false;
6048a4dda33SDimitry Andric 
6058a4dda33SDimitry Andric   // Make sure the branch is the only user of the AND.
6068a4dda33SDimitry Andric   if (MaskReg.isValid()) {
6078a4dda33SDimitry Andric     if (BNEOp0 == DestReg && !MBBI->getOperand(0).isKill())
6088a4dda33SDimitry Andric       return false;
6098a4dda33SDimitry Andric     if (BNEOp1 == DestReg && !MBBI->getOperand(1).isKill())
6108a4dda33SDimitry Andric       return false;
6118a4dda33SDimitry Andric   }
6128a4dda33SDimitry Andric 
613bdd1243dSDimitry Andric   ToErase.push_back(&*MBBI);
614bdd1243dSDimitry Andric   LoopHeadBNETarget = MBBI->getOperand(2).getMBB();
615bdd1243dSDimitry Andric   MBBI = skipDebugInstructionsForward(std::next(MBBI), E);
616bdd1243dSDimitry Andric   if (MBBI != E)
617bdd1243dSDimitry Andric     return false;
618bdd1243dSDimitry Andric 
619bdd1243dSDimitry Andric   MBB.removeSuccessor(LoopHeadBNETarget);
620bdd1243dSDimitry Andric   for (auto *MI : ToErase)
621bdd1243dSDimitry Andric     MI->eraseFromParent();
622bdd1243dSDimitry Andric   return true;
623bdd1243dSDimitry Andric }
624bdd1243dSDimitry Andric 
6255ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicCmpXchg(
6265ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked,
6275ffd83dbSDimitry Andric     int Width, MachineBasicBlock::iterator &NextMBBI) {
6285ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
6295ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
6305ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
6315ffd83dbSDimitry Andric   auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
6325ffd83dbSDimitry Andric   auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
6335ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
6345ffd83dbSDimitry Andric 
635bdd1243dSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
636bdd1243dSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
637bdd1243dSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
638bdd1243dSDimitry Andric   Register CmpValReg = MI.getOperand(3).getReg();
639bdd1243dSDimitry Andric   Register NewValReg = MI.getOperand(4).getReg();
640bdd1243dSDimitry Andric   Register MaskReg = IsMasked ? MI.getOperand(5).getReg() : Register();
641bdd1243dSDimitry Andric 
642bdd1243dSDimitry Andric   MachineBasicBlock *LoopHeadBNETarget = DoneMBB;
643bdd1243dSDimitry Andric   tryToFoldBNEOnCmpXchgResult(MBB, std::next(MBBI), DestReg, CmpValReg, MaskReg,
644bdd1243dSDimitry Andric                               LoopHeadBNETarget);
645bdd1243dSDimitry Andric 
6465ffd83dbSDimitry Andric   // Insert new MBBs.
6475ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopHeadMBB);
6485ffd83dbSDimitry Andric   MF->insert(++LoopHeadMBB->getIterator(), LoopTailMBB);
6495ffd83dbSDimitry Andric   MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
6505ffd83dbSDimitry Andric 
6515ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
6525ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopTailMBB);
653bdd1243dSDimitry Andric   LoopHeadMBB->addSuccessor(LoopHeadBNETarget);
6545ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(DoneMBB);
6555ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(LoopHeadMBB);
6565ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
6575ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
6585ffd83dbSDimitry Andric   MBB.addSuccessor(LoopHeadMBB);
6595ffd83dbSDimitry Andric 
6605ffd83dbSDimitry Andric   AtomicOrdering Ordering =
6615ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(IsMasked ? 6 : 5).getImm());
6625ffd83dbSDimitry Andric 
6635ffd83dbSDimitry Andric   if (!IsMasked) {
6645ffd83dbSDimitry Andric     // .loophead:
6655ffd83dbSDimitry Andric     //   lr.[w|d] dest, (addr)
6665ffd83dbSDimitry Andric     //   bne dest, cmpval, done
667*5f757f3fSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width, STI)),
668*5f757f3fSDimitry Andric             DestReg)
6695ffd83dbSDimitry Andric         .addReg(AddrReg);
6705ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
6715ffd83dbSDimitry Andric         .addReg(DestReg)
6725ffd83dbSDimitry Andric         .addReg(CmpValReg)
673bdd1243dSDimitry Andric         .addMBB(LoopHeadBNETarget);
6745ffd83dbSDimitry Andric     // .looptail:
6755ffd83dbSDimitry Andric     //   sc.[w|d] scratch, newval, (addr)
6765ffd83dbSDimitry Andric     //   bnez scratch, loophead
677*5f757f3fSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width, STI)),
678*5f757f3fSDimitry Andric             ScratchReg)
6795ffd83dbSDimitry Andric         .addReg(AddrReg)
6805ffd83dbSDimitry Andric         .addReg(NewValReg);
6815ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
6825ffd83dbSDimitry Andric         .addReg(ScratchReg)
6835ffd83dbSDimitry Andric         .addReg(RISCV::X0)
6845ffd83dbSDimitry Andric         .addMBB(LoopHeadMBB);
6855ffd83dbSDimitry Andric   } else {
6865ffd83dbSDimitry Andric     // .loophead:
6875ffd83dbSDimitry Andric     //   lr.w dest, (addr)
6885ffd83dbSDimitry Andric     //   and scratch, dest, mask
6895ffd83dbSDimitry Andric     //   bne scratch, cmpval, done
6905ffd83dbSDimitry Andric     Register MaskReg = MI.getOperand(5).getReg();
691*5f757f3fSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width, STI)),
692*5f757f3fSDimitry Andric             DestReg)
6935ffd83dbSDimitry Andric         .addReg(AddrReg);
6945ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), ScratchReg)
6955ffd83dbSDimitry Andric         .addReg(DestReg)
6965ffd83dbSDimitry Andric         .addReg(MaskReg);
6975ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
6985ffd83dbSDimitry Andric         .addReg(ScratchReg)
6995ffd83dbSDimitry Andric         .addReg(CmpValReg)
700bdd1243dSDimitry Andric         .addMBB(LoopHeadBNETarget);
7015ffd83dbSDimitry Andric 
7025ffd83dbSDimitry Andric     // .looptail:
7035ffd83dbSDimitry Andric     //   xor scratch, dest, newval
7045ffd83dbSDimitry Andric     //   and scratch, scratch, mask
7055ffd83dbSDimitry Andric     //   xor scratch, dest, scratch
7065ffd83dbSDimitry Andric     //   sc.w scratch, scratch, (adrr)
7075ffd83dbSDimitry Andric     //   bnez scratch, loophead
7085ffd83dbSDimitry Andric     insertMaskedMerge(TII, DL, LoopTailMBB, ScratchReg, DestReg, NewValReg,
7095ffd83dbSDimitry Andric                       MaskReg, ScratchReg);
710*5f757f3fSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width, STI)),
711*5f757f3fSDimitry Andric             ScratchReg)
7125ffd83dbSDimitry Andric         .addReg(AddrReg)
7135ffd83dbSDimitry Andric         .addReg(ScratchReg);
7145ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
7155ffd83dbSDimitry Andric         .addReg(ScratchReg)
7165ffd83dbSDimitry Andric         .addReg(RISCV::X0)
7175ffd83dbSDimitry Andric         .addMBB(LoopHeadMBB);
7185ffd83dbSDimitry Andric   }
7195ffd83dbSDimitry Andric 
7205ffd83dbSDimitry Andric   NextMBBI = MBB.end();
7215ffd83dbSDimitry Andric   MI.eraseFromParent();
7225ffd83dbSDimitry Andric 
7235ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
7245ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
7255ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
7265ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
7275ffd83dbSDimitry Andric 
7285ffd83dbSDimitry Andric   return true;
7295ffd83dbSDimitry Andric }
7305ffd83dbSDimitry Andric 
7315ffd83dbSDimitry Andric } // end of anonymous namespace
7325ffd83dbSDimitry Andric 
7335ffd83dbSDimitry Andric INITIALIZE_PASS(RISCVExpandAtomicPseudo, "riscv-expand-atomic-pseudo",
7345ffd83dbSDimitry Andric                 RISCV_EXPAND_ATOMIC_PSEUDO_NAME, false, false)
7355ffd83dbSDimitry Andric 
7365ffd83dbSDimitry Andric namespace llvm {
7375ffd83dbSDimitry Andric 
7385ffd83dbSDimitry Andric FunctionPass *createRISCVExpandAtomicPseudoPass() {
7395ffd83dbSDimitry Andric   return new RISCVExpandAtomicPseudo();
7405ffd83dbSDimitry Andric }
7415ffd83dbSDimitry Andric 
7425ffd83dbSDimitry Andric } // end of namespace llvm
743