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