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