xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVExpandAtomicPseudoInsts.cpp (revision 8a4dda33d67586ca2624f2a38417baa03a533a7f)
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:
335ffd83dbSDimitry Andric   const RISCVInstrInfo *TII;
345ffd83dbSDimitry Andric   static char ID;
355ffd83dbSDimitry Andric 
365ffd83dbSDimitry Andric   RISCVExpandAtomicPseudo() : MachineFunctionPass(ID) {
375ffd83dbSDimitry Andric     initializeRISCVExpandAtomicPseudoPass(*PassRegistry::getPassRegistry());
385ffd83dbSDimitry Andric   }
395ffd83dbSDimitry Andric 
405ffd83dbSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
415ffd83dbSDimitry Andric 
425ffd83dbSDimitry Andric   StringRef getPassName() const override {
435ffd83dbSDimitry Andric     return RISCV_EXPAND_ATOMIC_PSEUDO_NAME;
445ffd83dbSDimitry Andric   }
455ffd83dbSDimitry Andric 
465ffd83dbSDimitry Andric private:
475ffd83dbSDimitry Andric   bool expandMBB(MachineBasicBlock &MBB);
485ffd83dbSDimitry Andric   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
495ffd83dbSDimitry Andric                 MachineBasicBlock::iterator &NextMBBI);
505ffd83dbSDimitry Andric   bool expandAtomicBinOp(MachineBasicBlock &MBB,
515ffd83dbSDimitry Andric                          MachineBasicBlock::iterator MBBI, AtomicRMWInst::BinOp,
525ffd83dbSDimitry Andric                          bool IsMasked, int Width,
535ffd83dbSDimitry Andric                          MachineBasicBlock::iterator &NextMBBI);
545ffd83dbSDimitry Andric   bool expandAtomicMinMaxOp(MachineBasicBlock &MBB,
555ffd83dbSDimitry Andric                             MachineBasicBlock::iterator MBBI,
565ffd83dbSDimitry Andric                             AtomicRMWInst::BinOp, bool IsMasked, int Width,
575ffd83dbSDimitry Andric                             MachineBasicBlock::iterator &NextMBBI);
585ffd83dbSDimitry Andric   bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
595ffd83dbSDimitry Andric                            MachineBasicBlock::iterator MBBI, bool IsMasked,
605ffd83dbSDimitry Andric                            int Width, MachineBasicBlock::iterator &NextMBBI);
6106c3fb27SDimitry Andric #ifndef NDEBUG
6206c3fb27SDimitry Andric   unsigned getInstSizeInBytes(const MachineFunction &MF) const {
6306c3fb27SDimitry Andric     unsigned Size = 0;
6406c3fb27SDimitry Andric     for (auto &MBB : MF)
6506c3fb27SDimitry Andric       for (auto &MI : MBB)
6606c3fb27SDimitry Andric         Size += TII->getInstSizeInBytes(MI);
6706c3fb27SDimitry Andric     return Size;
6806c3fb27SDimitry Andric   }
6906c3fb27SDimitry Andric #endif
705ffd83dbSDimitry Andric };
715ffd83dbSDimitry Andric 
725ffd83dbSDimitry Andric char RISCVExpandAtomicPseudo::ID = 0;
735ffd83dbSDimitry Andric 
745ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::runOnMachineFunction(MachineFunction &MF) {
7506c3fb27SDimitry Andric   TII = MF.getSubtarget<RISCVSubtarget>().getInstrInfo();
7606c3fb27SDimitry Andric 
7706c3fb27SDimitry Andric #ifndef NDEBUG
7806c3fb27SDimitry Andric   const unsigned OldSize = getInstSizeInBytes(MF);
7906c3fb27SDimitry Andric #endif
8006c3fb27SDimitry Andric 
815ffd83dbSDimitry Andric   bool Modified = false;
825ffd83dbSDimitry Andric   for (auto &MBB : MF)
835ffd83dbSDimitry Andric     Modified |= expandMBB(MBB);
8406c3fb27SDimitry Andric 
8506c3fb27SDimitry Andric #ifndef NDEBUG
8606c3fb27SDimitry Andric   const unsigned NewSize = getInstSizeInBytes(MF);
8706c3fb27SDimitry Andric   assert(OldSize >= NewSize);
8806c3fb27SDimitry Andric #endif
895ffd83dbSDimitry Andric   return Modified;
905ffd83dbSDimitry Andric }
915ffd83dbSDimitry Andric 
925ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMBB(MachineBasicBlock &MBB) {
935ffd83dbSDimitry Andric   bool Modified = false;
945ffd83dbSDimitry Andric 
955ffd83dbSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
965ffd83dbSDimitry Andric   while (MBBI != E) {
975ffd83dbSDimitry Andric     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
985ffd83dbSDimitry Andric     Modified |= expandMI(MBB, MBBI, NMBBI);
995ffd83dbSDimitry Andric     MBBI = NMBBI;
1005ffd83dbSDimitry Andric   }
1015ffd83dbSDimitry Andric 
1025ffd83dbSDimitry Andric   return Modified;
1035ffd83dbSDimitry Andric }
1045ffd83dbSDimitry Andric 
1055ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMI(MachineBasicBlock &MBB,
1065ffd83dbSDimitry Andric                                        MachineBasicBlock::iterator MBBI,
1075ffd83dbSDimitry Andric                                        MachineBasicBlock::iterator &NextMBBI) {
1081fd87a68SDimitry Andric   // RISCVInstrInfo::getInstSizeInBytes expects that the total size of the
1091fd87a68SDimitry Andric   // expanded instructions for each pseudo is correct in the Size field of the
1101fd87a68SDimitry Andric   // tablegen definition for the pseudo.
1115ffd83dbSDimitry Andric   switch (MBBI->getOpcode()) {
1125ffd83dbSDimitry Andric   case RISCV::PseudoAtomicLoadNand32:
1135ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 32,
1145ffd83dbSDimitry Andric                              NextMBBI);
1155ffd83dbSDimitry Andric   case RISCV::PseudoAtomicLoadNand64:
1165ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 64,
1175ffd83dbSDimitry Andric                              NextMBBI);
1185ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicSwap32:
1195ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, true, 32,
1205ffd83dbSDimitry Andric                              NextMBBI);
1215ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadAdd32:
1225ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Add, true, 32, NextMBBI);
1235ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadSub32:
1245ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Sub, true, 32, NextMBBI);
1255ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadNand32:
1265ffd83dbSDimitry Andric     return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, true, 32,
1275ffd83dbSDimitry Andric                              NextMBBI);
1285ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadMax32:
1295ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Max, true, 32,
1305ffd83dbSDimitry Andric                                 NextMBBI);
1315ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadMin32:
1325ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Min, true, 32,
1335ffd83dbSDimitry Andric                                 NextMBBI);
1345ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadUMax32:
1355ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMax, true, 32,
1365ffd83dbSDimitry Andric                                 NextMBBI);
1375ffd83dbSDimitry Andric   case RISCV::PseudoMaskedAtomicLoadUMin32:
1385ffd83dbSDimitry Andric     return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, true, 32,
1395ffd83dbSDimitry Andric                                 NextMBBI);
1405ffd83dbSDimitry Andric   case RISCV::PseudoCmpXchg32:
1415ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, false, 32, NextMBBI);
1425ffd83dbSDimitry Andric   case RISCV::PseudoCmpXchg64:
1435ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
1445ffd83dbSDimitry Andric   case RISCV::PseudoMaskedCmpXchg32:
1455ffd83dbSDimitry Andric     return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
1465ffd83dbSDimitry Andric   }
1475ffd83dbSDimitry Andric 
1485ffd83dbSDimitry Andric   return false;
1495ffd83dbSDimitry Andric }
1505ffd83dbSDimitry Andric 
1515ffd83dbSDimitry Andric static unsigned getLRForRMW32(AtomicOrdering Ordering) {
1525ffd83dbSDimitry Andric   switch (Ordering) {
1535ffd83dbSDimitry Andric   default:
1545ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
1555ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
1565ffd83dbSDimitry Andric     return RISCV::LR_W;
1575ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
1585ffd83dbSDimitry Andric     return RISCV::LR_W_AQ;
1595ffd83dbSDimitry Andric   case AtomicOrdering::Release:
1605ffd83dbSDimitry Andric     return RISCV::LR_W;
1615ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
1625ffd83dbSDimitry Andric     return RISCV::LR_W_AQ;
1635ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
1645ffd83dbSDimitry Andric     return RISCV::LR_W_AQ_RL;
1655ffd83dbSDimitry Andric   }
1665ffd83dbSDimitry Andric }
1675ffd83dbSDimitry Andric 
1685ffd83dbSDimitry Andric static unsigned getSCForRMW32(AtomicOrdering Ordering) {
1695ffd83dbSDimitry Andric   switch (Ordering) {
1705ffd83dbSDimitry Andric   default:
1715ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
1725ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
1735ffd83dbSDimitry Andric     return RISCV::SC_W;
1745ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
1755ffd83dbSDimitry Andric     return RISCV::SC_W;
1765ffd83dbSDimitry Andric   case AtomicOrdering::Release:
1775ffd83dbSDimitry Andric     return RISCV::SC_W_RL;
1785ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
1795ffd83dbSDimitry Andric     return RISCV::SC_W_RL;
1805ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
18106c3fb27SDimitry Andric     return RISCV::SC_W_RL;
1825ffd83dbSDimitry Andric   }
1835ffd83dbSDimitry Andric }
1845ffd83dbSDimitry Andric 
1855ffd83dbSDimitry Andric static unsigned getLRForRMW64(AtomicOrdering Ordering) {
1865ffd83dbSDimitry Andric   switch (Ordering) {
1875ffd83dbSDimitry Andric   default:
1885ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
1895ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
1905ffd83dbSDimitry Andric     return RISCV::LR_D;
1915ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
1925ffd83dbSDimitry Andric     return RISCV::LR_D_AQ;
1935ffd83dbSDimitry Andric   case AtomicOrdering::Release:
1945ffd83dbSDimitry Andric     return RISCV::LR_D;
1955ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
1965ffd83dbSDimitry Andric     return RISCV::LR_D_AQ;
1975ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
1985ffd83dbSDimitry Andric     return RISCV::LR_D_AQ_RL;
1995ffd83dbSDimitry Andric   }
2005ffd83dbSDimitry Andric }
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric static unsigned getSCForRMW64(AtomicOrdering Ordering) {
2035ffd83dbSDimitry Andric   switch (Ordering) {
2045ffd83dbSDimitry Andric   default:
2055ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicOrdering");
2065ffd83dbSDimitry Andric   case AtomicOrdering::Monotonic:
2075ffd83dbSDimitry Andric     return RISCV::SC_D;
2085ffd83dbSDimitry Andric   case AtomicOrdering::Acquire:
2095ffd83dbSDimitry Andric     return RISCV::SC_D;
2105ffd83dbSDimitry Andric   case AtomicOrdering::Release:
2115ffd83dbSDimitry Andric     return RISCV::SC_D_RL;
2125ffd83dbSDimitry Andric   case AtomicOrdering::AcquireRelease:
2135ffd83dbSDimitry Andric     return RISCV::SC_D_RL;
2145ffd83dbSDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
21506c3fb27SDimitry Andric     return RISCV::SC_D_RL;
2165ffd83dbSDimitry Andric   }
2175ffd83dbSDimitry Andric }
2185ffd83dbSDimitry Andric 
2195ffd83dbSDimitry Andric static unsigned getLRForRMW(AtomicOrdering Ordering, int Width) {
2205ffd83dbSDimitry Andric   if (Width == 32)
2215ffd83dbSDimitry Andric     return getLRForRMW32(Ordering);
2225ffd83dbSDimitry Andric   if (Width == 64)
2235ffd83dbSDimitry Andric     return getLRForRMW64(Ordering);
2245ffd83dbSDimitry Andric   llvm_unreachable("Unexpected LR width\n");
2255ffd83dbSDimitry Andric }
2265ffd83dbSDimitry Andric 
2275ffd83dbSDimitry Andric static unsigned getSCForRMW(AtomicOrdering Ordering, int Width) {
2285ffd83dbSDimitry Andric   if (Width == 32)
2295ffd83dbSDimitry Andric     return getSCForRMW32(Ordering);
2305ffd83dbSDimitry Andric   if (Width == 64)
2315ffd83dbSDimitry Andric     return getSCForRMW64(Ordering);
2325ffd83dbSDimitry Andric   llvm_unreachable("Unexpected SC width\n");
2335ffd83dbSDimitry Andric }
2345ffd83dbSDimitry Andric 
2355ffd83dbSDimitry Andric static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI,
2365ffd83dbSDimitry Andric                                    DebugLoc DL, MachineBasicBlock *ThisMBB,
2375ffd83dbSDimitry Andric                                    MachineBasicBlock *LoopMBB,
2385ffd83dbSDimitry Andric                                    MachineBasicBlock *DoneMBB,
2395ffd83dbSDimitry Andric                                    AtomicRMWInst::BinOp BinOp, int Width) {
2405ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
2415ffd83dbSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
2425ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
2435ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(3).getReg();
2445ffd83dbSDimitry Andric   AtomicOrdering Ordering =
2455ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(4).getImm());
2465ffd83dbSDimitry Andric 
2475ffd83dbSDimitry Andric   // .loop:
2485ffd83dbSDimitry Andric   //   lr.[w|d] dest, (addr)
2495ffd83dbSDimitry Andric   //   binop scratch, dest, val
2505ffd83dbSDimitry Andric   //   sc.[w|d] scratch, scratch, (addr)
2515ffd83dbSDimitry Andric   //   bnez scratch, loop
2525ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
2535ffd83dbSDimitry Andric       .addReg(AddrReg);
2545ffd83dbSDimitry Andric   switch (BinOp) {
2555ffd83dbSDimitry Andric   default:
2565ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
2575ffd83dbSDimitry Andric   case AtomicRMWInst::Nand:
2585ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
2595ffd83dbSDimitry Andric         .addReg(DestReg)
2605ffd83dbSDimitry Andric         .addReg(IncrReg);
2615ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
2625ffd83dbSDimitry Andric         .addReg(ScratchReg)
2635ffd83dbSDimitry Andric         .addImm(-1);
2645ffd83dbSDimitry Andric     break;
2655ffd83dbSDimitry Andric   }
2665ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
2675ffd83dbSDimitry Andric       .addReg(AddrReg)
2685ffd83dbSDimitry Andric       .addReg(ScratchReg);
2695ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
2705ffd83dbSDimitry Andric       .addReg(ScratchReg)
2715ffd83dbSDimitry Andric       .addReg(RISCV::X0)
2725ffd83dbSDimitry Andric       .addMBB(LoopMBB);
2735ffd83dbSDimitry Andric }
2745ffd83dbSDimitry Andric 
2755ffd83dbSDimitry Andric static void insertMaskedMerge(const RISCVInstrInfo *TII, DebugLoc DL,
2765ffd83dbSDimitry Andric                               MachineBasicBlock *MBB, Register DestReg,
2775ffd83dbSDimitry Andric                               Register OldValReg, Register NewValReg,
2785ffd83dbSDimitry Andric                               Register MaskReg, Register ScratchReg) {
2795ffd83dbSDimitry Andric   assert(OldValReg != ScratchReg && "OldValReg and ScratchReg must be unique");
2805ffd83dbSDimitry Andric   assert(OldValReg != MaskReg && "OldValReg and MaskReg must be unique");
2815ffd83dbSDimitry Andric   assert(ScratchReg != MaskReg && "ScratchReg and MaskReg must be unique");
2825ffd83dbSDimitry Andric 
2835ffd83dbSDimitry Andric   // We select bits from newval and oldval using:
2845ffd83dbSDimitry Andric   // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
2855ffd83dbSDimitry Andric   // r = oldval ^ ((oldval ^ newval) & masktargetdata);
2865ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::XOR), ScratchReg)
2875ffd83dbSDimitry Andric       .addReg(OldValReg)
2885ffd83dbSDimitry Andric       .addReg(NewValReg);
2895ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::AND), ScratchReg)
2905ffd83dbSDimitry Andric       .addReg(ScratchReg)
2915ffd83dbSDimitry Andric       .addReg(MaskReg);
2925ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::XOR), DestReg)
2935ffd83dbSDimitry Andric       .addReg(OldValReg)
2945ffd83dbSDimitry Andric       .addReg(ScratchReg);
2955ffd83dbSDimitry Andric }
2965ffd83dbSDimitry Andric 
2975ffd83dbSDimitry Andric static void doMaskedAtomicBinOpExpansion(
2985ffd83dbSDimitry Andric     const RISCVInstrInfo *TII, MachineInstr &MI, DebugLoc DL,
2995ffd83dbSDimitry Andric     MachineBasicBlock *ThisMBB, MachineBasicBlock *LoopMBB,
3005ffd83dbSDimitry Andric     MachineBasicBlock *DoneMBB, AtomicRMWInst::BinOp BinOp, int Width) {
3015ffd83dbSDimitry Andric   assert(Width == 32 && "Should never need to expand masked 64-bit operations");
3025ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
3035ffd83dbSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
3045ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
3055ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(3).getReg();
3065ffd83dbSDimitry Andric   Register MaskReg = MI.getOperand(4).getReg();
3075ffd83dbSDimitry Andric   AtomicOrdering Ordering =
3085ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(5).getImm());
3095ffd83dbSDimitry Andric 
3105ffd83dbSDimitry Andric   // .loop:
3115ffd83dbSDimitry Andric   //   lr.w destreg, (alignedaddr)
3125ffd83dbSDimitry Andric   //   binop scratch, destreg, incr
3135ffd83dbSDimitry Andric   //   xor scratch, destreg, scratch
3145ffd83dbSDimitry Andric   //   and scratch, scratch, masktargetdata
3155ffd83dbSDimitry Andric   //   xor scratch, destreg, scratch
3165ffd83dbSDimitry Andric   //   sc.w scratch, scratch, (alignedaddr)
3175ffd83dbSDimitry Andric   //   bnez scratch, loop
3185ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
3195ffd83dbSDimitry Andric       .addReg(AddrReg);
3205ffd83dbSDimitry Andric   switch (BinOp) {
3215ffd83dbSDimitry Andric   default:
3225ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
3235ffd83dbSDimitry Andric   case AtomicRMWInst::Xchg:
3245ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::ADDI), ScratchReg)
3255ffd83dbSDimitry Andric         .addReg(IncrReg)
3265ffd83dbSDimitry Andric         .addImm(0);
3275ffd83dbSDimitry Andric     break;
3285ffd83dbSDimitry Andric   case AtomicRMWInst::Add:
3295ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg)
3305ffd83dbSDimitry Andric         .addReg(DestReg)
3315ffd83dbSDimitry Andric         .addReg(IncrReg);
3325ffd83dbSDimitry Andric     break;
3335ffd83dbSDimitry Andric   case AtomicRMWInst::Sub:
3345ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::SUB), ScratchReg)
3355ffd83dbSDimitry Andric         .addReg(DestReg)
3365ffd83dbSDimitry Andric         .addReg(IncrReg);
3375ffd83dbSDimitry Andric     break;
3385ffd83dbSDimitry Andric   case AtomicRMWInst::Nand:
3395ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
3405ffd83dbSDimitry Andric         .addReg(DestReg)
3415ffd83dbSDimitry Andric         .addReg(IncrReg);
3425ffd83dbSDimitry Andric     BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
3435ffd83dbSDimitry Andric         .addReg(ScratchReg)
3445ffd83dbSDimitry Andric         .addImm(-1);
3455ffd83dbSDimitry Andric     break;
3465ffd83dbSDimitry Andric   }
3475ffd83dbSDimitry Andric 
3485ffd83dbSDimitry Andric   insertMaskedMerge(TII, DL, LoopMBB, ScratchReg, DestReg, ScratchReg, MaskReg,
3495ffd83dbSDimitry Andric                     ScratchReg);
3505ffd83dbSDimitry Andric 
3515ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg)
3525ffd83dbSDimitry Andric       .addReg(AddrReg)
3535ffd83dbSDimitry Andric       .addReg(ScratchReg);
3545ffd83dbSDimitry Andric   BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
3555ffd83dbSDimitry Andric       .addReg(ScratchReg)
3565ffd83dbSDimitry Andric       .addReg(RISCV::X0)
3575ffd83dbSDimitry Andric       .addMBB(LoopMBB);
3585ffd83dbSDimitry Andric }
3595ffd83dbSDimitry Andric 
3605ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicBinOp(
3615ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
3625ffd83dbSDimitry Andric     AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
3635ffd83dbSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
3645ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
3655ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
3665ffd83dbSDimitry Andric 
3675ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
3685ffd83dbSDimitry Andric   auto LoopMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
3695ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
3705ffd83dbSDimitry Andric 
3715ffd83dbSDimitry Andric   // Insert new MBBs.
3725ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopMBB);
3735ffd83dbSDimitry Andric   MF->insert(++LoopMBB->getIterator(), DoneMBB);
3745ffd83dbSDimitry Andric 
3755ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
3765ffd83dbSDimitry Andric   LoopMBB->addSuccessor(LoopMBB);
3775ffd83dbSDimitry Andric   LoopMBB->addSuccessor(DoneMBB);
3785ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
3795ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
3805ffd83dbSDimitry Andric   MBB.addSuccessor(LoopMBB);
3815ffd83dbSDimitry Andric 
3825ffd83dbSDimitry Andric   if (!IsMasked)
3835ffd83dbSDimitry Andric     doAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp, Width);
3845ffd83dbSDimitry Andric   else
3855ffd83dbSDimitry Andric     doMaskedAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp,
3865ffd83dbSDimitry Andric                                  Width);
3875ffd83dbSDimitry Andric 
3885ffd83dbSDimitry Andric   NextMBBI = MBB.end();
3895ffd83dbSDimitry Andric   MI.eraseFromParent();
3905ffd83dbSDimitry Andric 
3915ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
3925ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopMBB);
3935ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
3945ffd83dbSDimitry Andric 
3955ffd83dbSDimitry Andric   return true;
3965ffd83dbSDimitry Andric }
3975ffd83dbSDimitry Andric 
3985ffd83dbSDimitry Andric static void insertSext(const RISCVInstrInfo *TII, DebugLoc DL,
3995ffd83dbSDimitry Andric                        MachineBasicBlock *MBB, Register ValReg,
4005ffd83dbSDimitry Andric                        Register ShamtReg) {
4015ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::SLL), ValReg)
4025ffd83dbSDimitry Andric       .addReg(ValReg)
4035ffd83dbSDimitry Andric       .addReg(ShamtReg);
4045ffd83dbSDimitry Andric   BuildMI(MBB, DL, TII->get(RISCV::SRA), ValReg)
4055ffd83dbSDimitry Andric       .addReg(ValReg)
4065ffd83dbSDimitry Andric       .addReg(ShamtReg);
4075ffd83dbSDimitry Andric }
4085ffd83dbSDimitry Andric 
4095ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicMinMaxOp(
4105ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
4115ffd83dbSDimitry Andric     AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
4125ffd83dbSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
4135ffd83dbSDimitry Andric   assert(IsMasked == true &&
4145ffd83dbSDimitry Andric          "Should only need to expand masked atomic max/min");
4155ffd83dbSDimitry Andric   assert(Width == 32 && "Should never need to expand masked 64-bit operations");
4165ffd83dbSDimitry Andric 
4175ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
4185ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
4195ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
4205ffd83dbSDimitry Andric   auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4215ffd83dbSDimitry Andric   auto LoopIfBodyMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4225ffd83dbSDimitry Andric   auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4235ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
4245ffd83dbSDimitry Andric 
4255ffd83dbSDimitry Andric   // Insert new MBBs.
4265ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopHeadMBB);
4275ffd83dbSDimitry Andric   MF->insert(++LoopHeadMBB->getIterator(), LoopIfBodyMBB);
4285ffd83dbSDimitry Andric   MF->insert(++LoopIfBodyMBB->getIterator(), LoopTailMBB);
4295ffd83dbSDimitry Andric   MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
4305ffd83dbSDimitry Andric 
4315ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
4325ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopIfBodyMBB);
4335ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopTailMBB);
4345ffd83dbSDimitry Andric   LoopIfBodyMBB->addSuccessor(LoopTailMBB);
4355ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(LoopHeadMBB);
4365ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(DoneMBB);
4375ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
4385ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
4395ffd83dbSDimitry Andric   MBB.addSuccessor(LoopHeadMBB);
4405ffd83dbSDimitry Andric 
4415ffd83dbSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
4425ffd83dbSDimitry Andric   Register Scratch1Reg = MI.getOperand(1).getReg();
4435ffd83dbSDimitry Andric   Register Scratch2Reg = MI.getOperand(2).getReg();
4445ffd83dbSDimitry Andric   Register AddrReg = MI.getOperand(3).getReg();
4455ffd83dbSDimitry Andric   Register IncrReg = MI.getOperand(4).getReg();
4465ffd83dbSDimitry Andric   Register MaskReg = MI.getOperand(5).getReg();
4475ffd83dbSDimitry Andric   bool IsSigned = BinOp == AtomicRMWInst::Min || BinOp == AtomicRMWInst::Max;
4485ffd83dbSDimitry Andric   AtomicOrdering Ordering =
4495ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(IsSigned ? 7 : 6).getImm());
4505ffd83dbSDimitry Andric 
4515ffd83dbSDimitry Andric   //
4525ffd83dbSDimitry Andric   // .loophead:
4535ffd83dbSDimitry Andric   //   lr.w destreg, (alignedaddr)
4545ffd83dbSDimitry Andric   //   and scratch2, destreg, mask
4555ffd83dbSDimitry Andric   //   mv scratch1, destreg
4565ffd83dbSDimitry Andric   //   [sext scratch2 if signed min/max]
4575ffd83dbSDimitry Andric   //   ifnochangeneeded scratch2, incr, .looptail
4585ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
4595ffd83dbSDimitry Andric       .addReg(AddrReg);
4605ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), Scratch2Reg)
4615ffd83dbSDimitry Andric       .addReg(DestReg)
4625ffd83dbSDimitry Andric       .addReg(MaskReg);
4635ffd83dbSDimitry Andric   BuildMI(LoopHeadMBB, DL, TII->get(RISCV::ADDI), Scratch1Reg)
4645ffd83dbSDimitry Andric       .addReg(DestReg)
4655ffd83dbSDimitry Andric       .addImm(0);
4665ffd83dbSDimitry Andric 
4675ffd83dbSDimitry Andric   switch (BinOp) {
4685ffd83dbSDimitry Andric   default:
4695ffd83dbSDimitry Andric     llvm_unreachable("Unexpected AtomicRMW BinOp");
4705ffd83dbSDimitry Andric   case AtomicRMWInst::Max: {
4715ffd83dbSDimitry Andric     insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
4725ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
4735ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
4745ffd83dbSDimitry Andric         .addReg(IncrReg)
4755ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
4765ffd83dbSDimitry Andric     break;
4775ffd83dbSDimitry Andric   }
4785ffd83dbSDimitry Andric   case AtomicRMWInst::Min: {
4795ffd83dbSDimitry Andric     insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
4805ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
4815ffd83dbSDimitry Andric         .addReg(IncrReg)
4825ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
4835ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
4845ffd83dbSDimitry Andric     break;
4855ffd83dbSDimitry Andric   }
4865ffd83dbSDimitry Andric   case AtomicRMWInst::UMax:
4875ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
4885ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
4895ffd83dbSDimitry Andric         .addReg(IncrReg)
4905ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
4915ffd83dbSDimitry Andric     break;
4925ffd83dbSDimitry Andric   case AtomicRMWInst::UMin:
4935ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
4945ffd83dbSDimitry Andric         .addReg(IncrReg)
4955ffd83dbSDimitry Andric         .addReg(Scratch2Reg)
4965ffd83dbSDimitry Andric         .addMBB(LoopTailMBB);
4975ffd83dbSDimitry Andric     break;
4985ffd83dbSDimitry Andric   }
4995ffd83dbSDimitry Andric 
5005ffd83dbSDimitry Andric   // .loopifbody:
5015ffd83dbSDimitry Andric   //   xor scratch1, destreg, incr
5025ffd83dbSDimitry Andric   //   and scratch1, scratch1, mask
5035ffd83dbSDimitry Andric   //   xor scratch1, destreg, scratch1
5045ffd83dbSDimitry Andric   insertMaskedMerge(TII, DL, LoopIfBodyMBB, Scratch1Reg, DestReg, IncrReg,
5055ffd83dbSDimitry Andric                     MaskReg, Scratch1Reg);
5065ffd83dbSDimitry Andric 
5075ffd83dbSDimitry Andric   // .looptail:
5085ffd83dbSDimitry Andric   //   sc.w scratch1, scratch1, (addr)
5095ffd83dbSDimitry Andric   //   bnez scratch1, loop
5105ffd83dbSDimitry Andric   BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), Scratch1Reg)
5115ffd83dbSDimitry Andric       .addReg(AddrReg)
5125ffd83dbSDimitry Andric       .addReg(Scratch1Reg);
5135ffd83dbSDimitry Andric   BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
5145ffd83dbSDimitry Andric       .addReg(Scratch1Reg)
5155ffd83dbSDimitry Andric       .addReg(RISCV::X0)
5165ffd83dbSDimitry Andric       .addMBB(LoopHeadMBB);
5175ffd83dbSDimitry Andric 
5185ffd83dbSDimitry Andric   NextMBBI = MBB.end();
5195ffd83dbSDimitry Andric   MI.eraseFromParent();
5205ffd83dbSDimitry Andric 
5215ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
5225ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
5235ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopIfBodyMBB);
5245ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
5255ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
5265ffd83dbSDimitry Andric 
5275ffd83dbSDimitry Andric   return true;
5285ffd83dbSDimitry Andric }
5295ffd83dbSDimitry Andric 
530bdd1243dSDimitry Andric // If a BNE on the cmpxchg comparison result immediately follows the cmpxchg
531bdd1243dSDimitry Andric // operation, it can be folded into the cmpxchg expansion by
532bdd1243dSDimitry Andric // modifying the branch within 'LoopHead' (which performs the same
533bdd1243dSDimitry Andric // comparison). This is a valid transformation because after altering the
534bdd1243dSDimitry Andric // LoopHead's BNE destination, the BNE following the cmpxchg becomes
535bdd1243dSDimitry Andric // redundant and and be deleted. In the case of a masked cmpxchg, an
536bdd1243dSDimitry Andric // appropriate AND and BNE must be matched.
537bdd1243dSDimitry Andric //
538bdd1243dSDimitry Andric // On success, returns true and deletes the matching BNE or AND+BNE, sets the
539bdd1243dSDimitry Andric // LoopHeadBNETarget argument to the target that should be used within the
540bdd1243dSDimitry Andric // loop head, and removes that block as a successor to MBB.
541bdd1243dSDimitry Andric bool tryToFoldBNEOnCmpXchgResult(MachineBasicBlock &MBB,
542bdd1243dSDimitry Andric                                  MachineBasicBlock::iterator MBBI,
543bdd1243dSDimitry Andric                                  Register DestReg, Register CmpValReg,
544bdd1243dSDimitry Andric                                  Register MaskReg,
545bdd1243dSDimitry Andric                                  MachineBasicBlock *&LoopHeadBNETarget) {
546bdd1243dSDimitry Andric   SmallVector<MachineInstr *> ToErase;
547bdd1243dSDimitry Andric   auto E = MBB.end();
548bdd1243dSDimitry Andric   if (MBBI == E)
549bdd1243dSDimitry Andric     return false;
550bdd1243dSDimitry Andric   MBBI = skipDebugInstructionsForward(MBBI, E);
551bdd1243dSDimitry Andric 
552bdd1243dSDimitry Andric   // If we have a masked cmpxchg, match AND dst, DestReg, MaskReg.
553bdd1243dSDimitry Andric   if (MaskReg.isValid()) {
554bdd1243dSDimitry Andric     if (MBBI == E || MBBI->getOpcode() != RISCV::AND)
555bdd1243dSDimitry Andric       return false;
556bdd1243dSDimitry Andric     Register ANDOp1 = MBBI->getOperand(1).getReg();
557bdd1243dSDimitry Andric     Register ANDOp2 = MBBI->getOperand(2).getReg();
558bdd1243dSDimitry Andric     if (!(ANDOp1 == DestReg && ANDOp2 == MaskReg) &&
559bdd1243dSDimitry Andric         !(ANDOp1 == MaskReg && ANDOp2 == DestReg))
560bdd1243dSDimitry Andric       return false;
561bdd1243dSDimitry Andric     // We now expect the BNE to use the result of the AND as an operand.
562bdd1243dSDimitry Andric     DestReg = MBBI->getOperand(0).getReg();
563bdd1243dSDimitry Andric     ToErase.push_back(&*MBBI);
564bdd1243dSDimitry Andric     MBBI = skipDebugInstructionsForward(std::next(MBBI), E);
565bdd1243dSDimitry Andric   }
566bdd1243dSDimitry Andric 
567bdd1243dSDimitry Andric   // Match BNE DestReg, MaskReg.
568bdd1243dSDimitry Andric   if (MBBI == E || MBBI->getOpcode() != RISCV::BNE)
569bdd1243dSDimitry Andric     return false;
570bdd1243dSDimitry Andric   Register BNEOp0 = MBBI->getOperand(0).getReg();
571bdd1243dSDimitry Andric   Register BNEOp1 = MBBI->getOperand(1).getReg();
572bdd1243dSDimitry Andric   if (!(BNEOp0 == DestReg && BNEOp1 == CmpValReg) &&
573bdd1243dSDimitry Andric       !(BNEOp0 == CmpValReg && BNEOp1 == DestReg))
574bdd1243dSDimitry Andric     return false;
575*8a4dda33SDimitry Andric 
576*8a4dda33SDimitry Andric   // Make sure the branch is the only user of the AND.
577*8a4dda33SDimitry Andric   if (MaskReg.isValid()) {
578*8a4dda33SDimitry Andric     if (BNEOp0 == DestReg && !MBBI->getOperand(0).isKill())
579*8a4dda33SDimitry Andric       return false;
580*8a4dda33SDimitry Andric     if (BNEOp1 == DestReg && !MBBI->getOperand(1).isKill())
581*8a4dda33SDimitry Andric       return false;
582*8a4dda33SDimitry Andric   }
583*8a4dda33SDimitry Andric 
584bdd1243dSDimitry Andric   ToErase.push_back(&*MBBI);
585bdd1243dSDimitry Andric   LoopHeadBNETarget = MBBI->getOperand(2).getMBB();
586bdd1243dSDimitry Andric   MBBI = skipDebugInstructionsForward(std::next(MBBI), E);
587bdd1243dSDimitry Andric   if (MBBI != E)
588bdd1243dSDimitry Andric     return false;
589bdd1243dSDimitry Andric 
590bdd1243dSDimitry Andric   MBB.removeSuccessor(LoopHeadBNETarget);
591bdd1243dSDimitry Andric   for (auto *MI : ToErase)
592bdd1243dSDimitry Andric     MI->eraseFromParent();
593bdd1243dSDimitry Andric   return true;
594bdd1243dSDimitry Andric }
595bdd1243dSDimitry Andric 
5965ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicCmpXchg(
5975ffd83dbSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked,
5985ffd83dbSDimitry Andric     int Width, MachineBasicBlock::iterator &NextMBBI) {
5995ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
6005ffd83dbSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
6015ffd83dbSDimitry Andric   MachineFunction *MF = MBB.getParent();
6025ffd83dbSDimitry Andric   auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
6035ffd83dbSDimitry Andric   auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
6045ffd83dbSDimitry Andric   auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
6055ffd83dbSDimitry Andric 
606bdd1243dSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
607bdd1243dSDimitry Andric   Register ScratchReg = MI.getOperand(1).getReg();
608bdd1243dSDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
609bdd1243dSDimitry Andric   Register CmpValReg = MI.getOperand(3).getReg();
610bdd1243dSDimitry Andric   Register NewValReg = MI.getOperand(4).getReg();
611bdd1243dSDimitry Andric   Register MaskReg = IsMasked ? MI.getOperand(5).getReg() : Register();
612bdd1243dSDimitry Andric 
613bdd1243dSDimitry Andric   MachineBasicBlock *LoopHeadBNETarget = DoneMBB;
614bdd1243dSDimitry Andric   tryToFoldBNEOnCmpXchgResult(MBB, std::next(MBBI), DestReg, CmpValReg, MaskReg,
615bdd1243dSDimitry Andric                               LoopHeadBNETarget);
616bdd1243dSDimitry Andric 
6175ffd83dbSDimitry Andric   // Insert new MBBs.
6185ffd83dbSDimitry Andric   MF->insert(++MBB.getIterator(), LoopHeadMBB);
6195ffd83dbSDimitry Andric   MF->insert(++LoopHeadMBB->getIterator(), LoopTailMBB);
6205ffd83dbSDimitry Andric   MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
6215ffd83dbSDimitry Andric 
6225ffd83dbSDimitry Andric   // Set up successors and transfer remaining instructions to DoneMBB.
6235ffd83dbSDimitry Andric   LoopHeadMBB->addSuccessor(LoopTailMBB);
624bdd1243dSDimitry Andric   LoopHeadMBB->addSuccessor(LoopHeadBNETarget);
6255ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(DoneMBB);
6265ffd83dbSDimitry Andric   LoopTailMBB->addSuccessor(LoopHeadMBB);
6275ffd83dbSDimitry Andric   DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
6285ffd83dbSDimitry Andric   DoneMBB->transferSuccessors(&MBB);
6295ffd83dbSDimitry Andric   MBB.addSuccessor(LoopHeadMBB);
6305ffd83dbSDimitry Andric 
6315ffd83dbSDimitry Andric   AtomicOrdering Ordering =
6325ffd83dbSDimitry Andric       static_cast<AtomicOrdering>(MI.getOperand(IsMasked ? 6 : 5).getImm());
6335ffd83dbSDimitry Andric 
6345ffd83dbSDimitry Andric   if (!IsMasked) {
6355ffd83dbSDimitry Andric     // .loophead:
6365ffd83dbSDimitry Andric     //   lr.[w|d] dest, (addr)
6375ffd83dbSDimitry Andric     //   bne dest, cmpval, done
6385ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
6395ffd83dbSDimitry Andric         .addReg(AddrReg);
6405ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
6415ffd83dbSDimitry Andric         .addReg(DestReg)
6425ffd83dbSDimitry Andric         .addReg(CmpValReg)
643bdd1243dSDimitry Andric         .addMBB(LoopHeadBNETarget);
6445ffd83dbSDimitry Andric     // .looptail:
6455ffd83dbSDimitry Andric     //   sc.[w|d] scratch, newval, (addr)
6465ffd83dbSDimitry Andric     //   bnez scratch, loophead
6475ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
6485ffd83dbSDimitry Andric         .addReg(AddrReg)
6495ffd83dbSDimitry Andric         .addReg(NewValReg);
6505ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
6515ffd83dbSDimitry Andric         .addReg(ScratchReg)
6525ffd83dbSDimitry Andric         .addReg(RISCV::X0)
6535ffd83dbSDimitry Andric         .addMBB(LoopHeadMBB);
6545ffd83dbSDimitry Andric   } else {
6555ffd83dbSDimitry Andric     // .loophead:
6565ffd83dbSDimitry Andric     //   lr.w dest, (addr)
6575ffd83dbSDimitry Andric     //   and scratch, dest, mask
6585ffd83dbSDimitry Andric     //   bne scratch, cmpval, done
6595ffd83dbSDimitry Andric     Register MaskReg = MI.getOperand(5).getReg();
6605ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
6615ffd83dbSDimitry Andric         .addReg(AddrReg);
6625ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), ScratchReg)
6635ffd83dbSDimitry Andric         .addReg(DestReg)
6645ffd83dbSDimitry Andric         .addReg(MaskReg);
6655ffd83dbSDimitry Andric     BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
6665ffd83dbSDimitry Andric         .addReg(ScratchReg)
6675ffd83dbSDimitry Andric         .addReg(CmpValReg)
668bdd1243dSDimitry Andric         .addMBB(LoopHeadBNETarget);
6695ffd83dbSDimitry Andric 
6705ffd83dbSDimitry Andric     // .looptail:
6715ffd83dbSDimitry Andric     //   xor scratch, dest, newval
6725ffd83dbSDimitry Andric     //   and scratch, scratch, mask
6735ffd83dbSDimitry Andric     //   xor scratch, dest, scratch
6745ffd83dbSDimitry Andric     //   sc.w scratch, scratch, (adrr)
6755ffd83dbSDimitry Andric     //   bnez scratch, loophead
6765ffd83dbSDimitry Andric     insertMaskedMerge(TII, DL, LoopTailMBB, ScratchReg, DestReg, NewValReg,
6775ffd83dbSDimitry Andric                       MaskReg, ScratchReg);
6785ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
6795ffd83dbSDimitry Andric         .addReg(AddrReg)
6805ffd83dbSDimitry Andric         .addReg(ScratchReg);
6815ffd83dbSDimitry Andric     BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
6825ffd83dbSDimitry Andric         .addReg(ScratchReg)
6835ffd83dbSDimitry Andric         .addReg(RISCV::X0)
6845ffd83dbSDimitry Andric         .addMBB(LoopHeadMBB);
6855ffd83dbSDimitry Andric   }
6865ffd83dbSDimitry Andric 
6875ffd83dbSDimitry Andric   NextMBBI = MBB.end();
6885ffd83dbSDimitry Andric   MI.eraseFromParent();
6895ffd83dbSDimitry Andric 
6905ffd83dbSDimitry Andric   LivePhysRegs LiveRegs;
6915ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
6925ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
6935ffd83dbSDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneMBB);
6945ffd83dbSDimitry Andric 
6955ffd83dbSDimitry Andric   return true;
6965ffd83dbSDimitry Andric }
6975ffd83dbSDimitry Andric 
6985ffd83dbSDimitry Andric } // end of anonymous namespace
6995ffd83dbSDimitry Andric 
7005ffd83dbSDimitry Andric INITIALIZE_PASS(RISCVExpandAtomicPseudo, "riscv-expand-atomic-pseudo",
7015ffd83dbSDimitry Andric                 RISCV_EXPAND_ATOMIC_PSEUDO_NAME, false, false)
7025ffd83dbSDimitry Andric 
7035ffd83dbSDimitry Andric namespace llvm {
7045ffd83dbSDimitry Andric 
7055ffd83dbSDimitry Andric FunctionPass *createRISCVExpandAtomicPseudoPass() {
7065ffd83dbSDimitry Andric   return new RISCVExpandAtomicPseudo();
7075ffd83dbSDimitry Andric }
7085ffd83dbSDimitry Andric 
7095ffd83dbSDimitry Andric } // end of namespace llvm
710