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