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