1*5ffd83dbSDimitry Andric //===-- RISCVExpandAtomicPseudoInsts.cpp - Expand atomic pseudo instrs. ---===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric // 9*5ffd83dbSDimitry Andric // This file contains a pass that expands atomic pseudo instructions into 10*5ffd83dbSDimitry Andric // target instructions. This pass should be run at the last possible moment, 11*5ffd83dbSDimitry Andric // avoiding the possibility for other passes to break the requirements for 12*5ffd83dbSDimitry Andric // forward progress in the LR/SC block. 13*5ffd83dbSDimitry Andric // 14*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 15*5ffd83dbSDimitry Andric 16*5ffd83dbSDimitry Andric #include "RISCV.h" 17*5ffd83dbSDimitry Andric #include "RISCVInstrInfo.h" 18*5ffd83dbSDimitry Andric #include "RISCVTargetMachine.h" 19*5ffd83dbSDimitry Andric 20*5ffd83dbSDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h" 21*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 22*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 23*5ffd83dbSDimitry Andric 24*5ffd83dbSDimitry Andric using namespace llvm; 25*5ffd83dbSDimitry Andric 26*5ffd83dbSDimitry Andric #define RISCV_EXPAND_ATOMIC_PSEUDO_NAME \ 27*5ffd83dbSDimitry Andric "RISCV atomic pseudo instruction expansion pass" 28*5ffd83dbSDimitry Andric 29*5ffd83dbSDimitry Andric namespace { 30*5ffd83dbSDimitry Andric 31*5ffd83dbSDimitry Andric class RISCVExpandAtomicPseudo : public MachineFunctionPass { 32*5ffd83dbSDimitry Andric public: 33*5ffd83dbSDimitry Andric const RISCVInstrInfo *TII; 34*5ffd83dbSDimitry Andric static char ID; 35*5ffd83dbSDimitry Andric 36*5ffd83dbSDimitry Andric RISCVExpandAtomicPseudo() : MachineFunctionPass(ID) { 37*5ffd83dbSDimitry Andric initializeRISCVExpandAtomicPseudoPass(*PassRegistry::getPassRegistry()); 38*5ffd83dbSDimitry Andric } 39*5ffd83dbSDimitry Andric 40*5ffd83dbSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 41*5ffd83dbSDimitry Andric 42*5ffd83dbSDimitry Andric StringRef getPassName() const override { 43*5ffd83dbSDimitry Andric return RISCV_EXPAND_ATOMIC_PSEUDO_NAME; 44*5ffd83dbSDimitry Andric } 45*5ffd83dbSDimitry Andric 46*5ffd83dbSDimitry Andric private: 47*5ffd83dbSDimitry Andric bool expandMBB(MachineBasicBlock &MBB); 48*5ffd83dbSDimitry Andric bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 49*5ffd83dbSDimitry Andric MachineBasicBlock::iterator &NextMBBI); 50*5ffd83dbSDimitry Andric bool expandAtomicBinOp(MachineBasicBlock &MBB, 51*5ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI, AtomicRMWInst::BinOp, 52*5ffd83dbSDimitry Andric bool IsMasked, int Width, 53*5ffd83dbSDimitry Andric MachineBasicBlock::iterator &NextMBBI); 54*5ffd83dbSDimitry Andric bool expandAtomicMinMaxOp(MachineBasicBlock &MBB, 55*5ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI, 56*5ffd83dbSDimitry Andric AtomicRMWInst::BinOp, bool IsMasked, int Width, 57*5ffd83dbSDimitry Andric MachineBasicBlock::iterator &NextMBBI); 58*5ffd83dbSDimitry Andric bool expandAtomicCmpXchg(MachineBasicBlock &MBB, 59*5ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI, bool IsMasked, 60*5ffd83dbSDimitry Andric int Width, MachineBasicBlock::iterator &NextMBBI); 61*5ffd83dbSDimitry Andric }; 62*5ffd83dbSDimitry Andric 63*5ffd83dbSDimitry Andric char RISCVExpandAtomicPseudo::ID = 0; 64*5ffd83dbSDimitry Andric 65*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::runOnMachineFunction(MachineFunction &MF) { 66*5ffd83dbSDimitry Andric TII = static_cast<const RISCVInstrInfo *>(MF.getSubtarget().getInstrInfo()); 67*5ffd83dbSDimitry Andric bool Modified = false; 68*5ffd83dbSDimitry Andric for (auto &MBB : MF) 69*5ffd83dbSDimitry Andric Modified |= expandMBB(MBB); 70*5ffd83dbSDimitry Andric return Modified; 71*5ffd83dbSDimitry Andric } 72*5ffd83dbSDimitry Andric 73*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMBB(MachineBasicBlock &MBB) { 74*5ffd83dbSDimitry Andric bool Modified = false; 75*5ffd83dbSDimitry Andric 76*5ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 77*5ffd83dbSDimitry Andric while (MBBI != E) { 78*5ffd83dbSDimitry Andric MachineBasicBlock::iterator NMBBI = std::next(MBBI); 79*5ffd83dbSDimitry Andric Modified |= expandMI(MBB, MBBI, NMBBI); 80*5ffd83dbSDimitry Andric MBBI = NMBBI; 81*5ffd83dbSDimitry Andric } 82*5ffd83dbSDimitry Andric 83*5ffd83dbSDimitry Andric return Modified; 84*5ffd83dbSDimitry Andric } 85*5ffd83dbSDimitry Andric 86*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandMI(MachineBasicBlock &MBB, 87*5ffd83dbSDimitry Andric MachineBasicBlock::iterator MBBI, 88*5ffd83dbSDimitry Andric MachineBasicBlock::iterator &NextMBBI) { 89*5ffd83dbSDimitry Andric // RISCVInstrInfo::getInstSizeInBytes hard-codes the number of expanded 90*5ffd83dbSDimitry Andric // instructions for each pseudo, and must be updated when adding new pseudos 91*5ffd83dbSDimitry Andric // or changing existing ones. 92*5ffd83dbSDimitry Andric switch (MBBI->getOpcode()) { 93*5ffd83dbSDimitry Andric case RISCV::PseudoAtomicLoadNand32: 94*5ffd83dbSDimitry Andric return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 32, 95*5ffd83dbSDimitry Andric NextMBBI); 96*5ffd83dbSDimitry Andric case RISCV::PseudoAtomicLoadNand64: 97*5ffd83dbSDimitry Andric return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 64, 98*5ffd83dbSDimitry Andric NextMBBI); 99*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicSwap32: 100*5ffd83dbSDimitry Andric return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, true, 32, 101*5ffd83dbSDimitry Andric NextMBBI); 102*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicLoadAdd32: 103*5ffd83dbSDimitry Andric return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Add, true, 32, NextMBBI); 104*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicLoadSub32: 105*5ffd83dbSDimitry Andric return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Sub, true, 32, NextMBBI); 106*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicLoadNand32: 107*5ffd83dbSDimitry Andric return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, true, 32, 108*5ffd83dbSDimitry Andric NextMBBI); 109*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicLoadMax32: 110*5ffd83dbSDimitry Andric return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Max, true, 32, 111*5ffd83dbSDimitry Andric NextMBBI); 112*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicLoadMin32: 113*5ffd83dbSDimitry Andric return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Min, true, 32, 114*5ffd83dbSDimitry Andric NextMBBI); 115*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicLoadUMax32: 116*5ffd83dbSDimitry Andric return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMax, true, 32, 117*5ffd83dbSDimitry Andric NextMBBI); 118*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedAtomicLoadUMin32: 119*5ffd83dbSDimitry Andric return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, true, 32, 120*5ffd83dbSDimitry Andric NextMBBI); 121*5ffd83dbSDimitry Andric case RISCV::PseudoCmpXchg32: 122*5ffd83dbSDimitry Andric return expandAtomicCmpXchg(MBB, MBBI, false, 32, NextMBBI); 123*5ffd83dbSDimitry Andric case RISCV::PseudoCmpXchg64: 124*5ffd83dbSDimitry Andric return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI); 125*5ffd83dbSDimitry Andric case RISCV::PseudoMaskedCmpXchg32: 126*5ffd83dbSDimitry Andric return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI); 127*5ffd83dbSDimitry Andric } 128*5ffd83dbSDimitry Andric 129*5ffd83dbSDimitry Andric return false; 130*5ffd83dbSDimitry Andric } 131*5ffd83dbSDimitry Andric 132*5ffd83dbSDimitry Andric static unsigned getLRForRMW32(AtomicOrdering Ordering) { 133*5ffd83dbSDimitry Andric switch (Ordering) { 134*5ffd83dbSDimitry Andric default: 135*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected AtomicOrdering"); 136*5ffd83dbSDimitry Andric case AtomicOrdering::Monotonic: 137*5ffd83dbSDimitry Andric return RISCV::LR_W; 138*5ffd83dbSDimitry Andric case AtomicOrdering::Acquire: 139*5ffd83dbSDimitry Andric return RISCV::LR_W_AQ; 140*5ffd83dbSDimitry Andric case AtomicOrdering::Release: 141*5ffd83dbSDimitry Andric return RISCV::LR_W; 142*5ffd83dbSDimitry Andric case AtomicOrdering::AcquireRelease: 143*5ffd83dbSDimitry Andric return RISCV::LR_W_AQ; 144*5ffd83dbSDimitry Andric case AtomicOrdering::SequentiallyConsistent: 145*5ffd83dbSDimitry Andric return RISCV::LR_W_AQ_RL; 146*5ffd83dbSDimitry Andric } 147*5ffd83dbSDimitry Andric } 148*5ffd83dbSDimitry Andric 149*5ffd83dbSDimitry Andric static unsigned getSCForRMW32(AtomicOrdering Ordering) { 150*5ffd83dbSDimitry Andric switch (Ordering) { 151*5ffd83dbSDimitry Andric default: 152*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected AtomicOrdering"); 153*5ffd83dbSDimitry Andric case AtomicOrdering::Monotonic: 154*5ffd83dbSDimitry Andric return RISCV::SC_W; 155*5ffd83dbSDimitry Andric case AtomicOrdering::Acquire: 156*5ffd83dbSDimitry Andric return RISCV::SC_W; 157*5ffd83dbSDimitry Andric case AtomicOrdering::Release: 158*5ffd83dbSDimitry Andric return RISCV::SC_W_RL; 159*5ffd83dbSDimitry Andric case AtomicOrdering::AcquireRelease: 160*5ffd83dbSDimitry Andric return RISCV::SC_W_RL; 161*5ffd83dbSDimitry Andric case AtomicOrdering::SequentiallyConsistent: 162*5ffd83dbSDimitry Andric return RISCV::SC_W_AQ_RL; 163*5ffd83dbSDimitry Andric } 164*5ffd83dbSDimitry Andric } 165*5ffd83dbSDimitry Andric 166*5ffd83dbSDimitry Andric static unsigned getLRForRMW64(AtomicOrdering Ordering) { 167*5ffd83dbSDimitry Andric switch (Ordering) { 168*5ffd83dbSDimitry Andric default: 169*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected AtomicOrdering"); 170*5ffd83dbSDimitry Andric case AtomicOrdering::Monotonic: 171*5ffd83dbSDimitry Andric return RISCV::LR_D; 172*5ffd83dbSDimitry Andric case AtomicOrdering::Acquire: 173*5ffd83dbSDimitry Andric return RISCV::LR_D_AQ; 174*5ffd83dbSDimitry Andric case AtomicOrdering::Release: 175*5ffd83dbSDimitry Andric return RISCV::LR_D; 176*5ffd83dbSDimitry Andric case AtomicOrdering::AcquireRelease: 177*5ffd83dbSDimitry Andric return RISCV::LR_D_AQ; 178*5ffd83dbSDimitry Andric case AtomicOrdering::SequentiallyConsistent: 179*5ffd83dbSDimitry Andric return RISCV::LR_D_AQ_RL; 180*5ffd83dbSDimitry Andric } 181*5ffd83dbSDimitry Andric } 182*5ffd83dbSDimitry Andric 183*5ffd83dbSDimitry Andric static unsigned getSCForRMW64(AtomicOrdering Ordering) { 184*5ffd83dbSDimitry Andric switch (Ordering) { 185*5ffd83dbSDimitry Andric default: 186*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected AtomicOrdering"); 187*5ffd83dbSDimitry Andric case AtomicOrdering::Monotonic: 188*5ffd83dbSDimitry Andric return RISCV::SC_D; 189*5ffd83dbSDimitry Andric case AtomicOrdering::Acquire: 190*5ffd83dbSDimitry Andric return RISCV::SC_D; 191*5ffd83dbSDimitry Andric case AtomicOrdering::Release: 192*5ffd83dbSDimitry Andric return RISCV::SC_D_RL; 193*5ffd83dbSDimitry Andric case AtomicOrdering::AcquireRelease: 194*5ffd83dbSDimitry Andric return RISCV::SC_D_RL; 195*5ffd83dbSDimitry Andric case AtomicOrdering::SequentiallyConsistent: 196*5ffd83dbSDimitry Andric return RISCV::SC_D_AQ_RL; 197*5ffd83dbSDimitry Andric } 198*5ffd83dbSDimitry Andric } 199*5ffd83dbSDimitry Andric 200*5ffd83dbSDimitry Andric static unsigned getLRForRMW(AtomicOrdering Ordering, int Width) { 201*5ffd83dbSDimitry Andric if (Width == 32) 202*5ffd83dbSDimitry Andric return getLRForRMW32(Ordering); 203*5ffd83dbSDimitry Andric if (Width == 64) 204*5ffd83dbSDimitry Andric return getLRForRMW64(Ordering); 205*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected LR width\n"); 206*5ffd83dbSDimitry Andric } 207*5ffd83dbSDimitry Andric 208*5ffd83dbSDimitry Andric static unsigned getSCForRMW(AtomicOrdering Ordering, int Width) { 209*5ffd83dbSDimitry Andric if (Width == 32) 210*5ffd83dbSDimitry Andric return getSCForRMW32(Ordering); 211*5ffd83dbSDimitry Andric if (Width == 64) 212*5ffd83dbSDimitry Andric return getSCForRMW64(Ordering); 213*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected SC width\n"); 214*5ffd83dbSDimitry Andric } 215*5ffd83dbSDimitry Andric 216*5ffd83dbSDimitry Andric static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI, 217*5ffd83dbSDimitry Andric DebugLoc DL, MachineBasicBlock *ThisMBB, 218*5ffd83dbSDimitry Andric MachineBasicBlock *LoopMBB, 219*5ffd83dbSDimitry Andric MachineBasicBlock *DoneMBB, 220*5ffd83dbSDimitry Andric AtomicRMWInst::BinOp BinOp, int Width) { 221*5ffd83dbSDimitry Andric Register DestReg = MI.getOperand(0).getReg(); 222*5ffd83dbSDimitry Andric Register ScratchReg = MI.getOperand(1).getReg(); 223*5ffd83dbSDimitry Andric Register AddrReg = MI.getOperand(2).getReg(); 224*5ffd83dbSDimitry Andric Register IncrReg = MI.getOperand(3).getReg(); 225*5ffd83dbSDimitry Andric AtomicOrdering Ordering = 226*5ffd83dbSDimitry Andric static_cast<AtomicOrdering>(MI.getOperand(4).getImm()); 227*5ffd83dbSDimitry Andric 228*5ffd83dbSDimitry Andric // .loop: 229*5ffd83dbSDimitry Andric // lr.[w|d] dest, (addr) 230*5ffd83dbSDimitry Andric // binop scratch, dest, val 231*5ffd83dbSDimitry Andric // sc.[w|d] scratch, scratch, (addr) 232*5ffd83dbSDimitry Andric // bnez scratch, loop 233*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg) 234*5ffd83dbSDimitry Andric .addReg(AddrReg); 235*5ffd83dbSDimitry Andric switch (BinOp) { 236*5ffd83dbSDimitry Andric default: 237*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 238*5ffd83dbSDimitry Andric case AtomicRMWInst::Nand: 239*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg) 240*5ffd83dbSDimitry Andric .addReg(DestReg) 241*5ffd83dbSDimitry Andric .addReg(IncrReg); 242*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg) 243*5ffd83dbSDimitry Andric .addReg(ScratchReg) 244*5ffd83dbSDimitry Andric .addImm(-1); 245*5ffd83dbSDimitry Andric break; 246*5ffd83dbSDimitry Andric } 247*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg) 248*5ffd83dbSDimitry Andric .addReg(AddrReg) 249*5ffd83dbSDimitry Andric .addReg(ScratchReg); 250*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::BNE)) 251*5ffd83dbSDimitry Andric .addReg(ScratchReg) 252*5ffd83dbSDimitry Andric .addReg(RISCV::X0) 253*5ffd83dbSDimitry Andric .addMBB(LoopMBB); 254*5ffd83dbSDimitry Andric } 255*5ffd83dbSDimitry Andric 256*5ffd83dbSDimitry Andric static void insertMaskedMerge(const RISCVInstrInfo *TII, DebugLoc DL, 257*5ffd83dbSDimitry Andric MachineBasicBlock *MBB, Register DestReg, 258*5ffd83dbSDimitry Andric Register OldValReg, Register NewValReg, 259*5ffd83dbSDimitry Andric Register MaskReg, Register ScratchReg) { 260*5ffd83dbSDimitry Andric assert(OldValReg != ScratchReg && "OldValReg and ScratchReg must be unique"); 261*5ffd83dbSDimitry Andric assert(OldValReg != MaskReg && "OldValReg and MaskReg must be unique"); 262*5ffd83dbSDimitry Andric assert(ScratchReg != MaskReg && "ScratchReg and MaskReg must be unique"); 263*5ffd83dbSDimitry Andric 264*5ffd83dbSDimitry Andric // We select bits from newval and oldval using: 265*5ffd83dbSDimitry Andric // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge 266*5ffd83dbSDimitry Andric // r = oldval ^ ((oldval ^ newval) & masktargetdata); 267*5ffd83dbSDimitry Andric BuildMI(MBB, DL, TII->get(RISCV::XOR), ScratchReg) 268*5ffd83dbSDimitry Andric .addReg(OldValReg) 269*5ffd83dbSDimitry Andric .addReg(NewValReg); 270*5ffd83dbSDimitry Andric BuildMI(MBB, DL, TII->get(RISCV::AND), ScratchReg) 271*5ffd83dbSDimitry Andric .addReg(ScratchReg) 272*5ffd83dbSDimitry Andric .addReg(MaskReg); 273*5ffd83dbSDimitry Andric BuildMI(MBB, DL, TII->get(RISCV::XOR), DestReg) 274*5ffd83dbSDimitry Andric .addReg(OldValReg) 275*5ffd83dbSDimitry Andric .addReg(ScratchReg); 276*5ffd83dbSDimitry Andric } 277*5ffd83dbSDimitry Andric 278*5ffd83dbSDimitry Andric static void doMaskedAtomicBinOpExpansion( 279*5ffd83dbSDimitry Andric const RISCVInstrInfo *TII, MachineInstr &MI, DebugLoc DL, 280*5ffd83dbSDimitry Andric MachineBasicBlock *ThisMBB, MachineBasicBlock *LoopMBB, 281*5ffd83dbSDimitry Andric MachineBasicBlock *DoneMBB, AtomicRMWInst::BinOp BinOp, int Width) { 282*5ffd83dbSDimitry Andric assert(Width == 32 && "Should never need to expand masked 64-bit operations"); 283*5ffd83dbSDimitry Andric Register DestReg = MI.getOperand(0).getReg(); 284*5ffd83dbSDimitry Andric Register ScratchReg = MI.getOperand(1).getReg(); 285*5ffd83dbSDimitry Andric Register AddrReg = MI.getOperand(2).getReg(); 286*5ffd83dbSDimitry Andric Register IncrReg = MI.getOperand(3).getReg(); 287*5ffd83dbSDimitry Andric Register MaskReg = MI.getOperand(4).getReg(); 288*5ffd83dbSDimitry Andric AtomicOrdering Ordering = 289*5ffd83dbSDimitry Andric static_cast<AtomicOrdering>(MI.getOperand(5).getImm()); 290*5ffd83dbSDimitry Andric 291*5ffd83dbSDimitry Andric // .loop: 292*5ffd83dbSDimitry Andric // lr.w destreg, (alignedaddr) 293*5ffd83dbSDimitry Andric // binop scratch, destreg, incr 294*5ffd83dbSDimitry Andric // xor scratch, destreg, scratch 295*5ffd83dbSDimitry Andric // and scratch, scratch, masktargetdata 296*5ffd83dbSDimitry Andric // xor scratch, destreg, scratch 297*5ffd83dbSDimitry Andric // sc.w scratch, scratch, (alignedaddr) 298*5ffd83dbSDimitry Andric // bnez scratch, loop 299*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg) 300*5ffd83dbSDimitry Andric .addReg(AddrReg); 301*5ffd83dbSDimitry Andric switch (BinOp) { 302*5ffd83dbSDimitry Andric default: 303*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 304*5ffd83dbSDimitry Andric case AtomicRMWInst::Xchg: 305*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::ADDI), ScratchReg) 306*5ffd83dbSDimitry Andric .addReg(IncrReg) 307*5ffd83dbSDimitry Andric .addImm(0); 308*5ffd83dbSDimitry Andric break; 309*5ffd83dbSDimitry Andric case AtomicRMWInst::Add: 310*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg) 311*5ffd83dbSDimitry Andric .addReg(DestReg) 312*5ffd83dbSDimitry Andric .addReg(IncrReg); 313*5ffd83dbSDimitry Andric break; 314*5ffd83dbSDimitry Andric case AtomicRMWInst::Sub: 315*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::SUB), ScratchReg) 316*5ffd83dbSDimitry Andric .addReg(DestReg) 317*5ffd83dbSDimitry Andric .addReg(IncrReg); 318*5ffd83dbSDimitry Andric break; 319*5ffd83dbSDimitry Andric case AtomicRMWInst::Nand: 320*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg) 321*5ffd83dbSDimitry Andric .addReg(DestReg) 322*5ffd83dbSDimitry Andric .addReg(IncrReg); 323*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg) 324*5ffd83dbSDimitry Andric .addReg(ScratchReg) 325*5ffd83dbSDimitry Andric .addImm(-1); 326*5ffd83dbSDimitry Andric break; 327*5ffd83dbSDimitry Andric } 328*5ffd83dbSDimitry Andric 329*5ffd83dbSDimitry Andric insertMaskedMerge(TII, DL, LoopMBB, ScratchReg, DestReg, ScratchReg, MaskReg, 330*5ffd83dbSDimitry Andric ScratchReg); 331*5ffd83dbSDimitry Andric 332*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg) 333*5ffd83dbSDimitry Andric .addReg(AddrReg) 334*5ffd83dbSDimitry Andric .addReg(ScratchReg); 335*5ffd83dbSDimitry Andric BuildMI(LoopMBB, DL, TII->get(RISCV::BNE)) 336*5ffd83dbSDimitry Andric .addReg(ScratchReg) 337*5ffd83dbSDimitry Andric .addReg(RISCV::X0) 338*5ffd83dbSDimitry Andric .addMBB(LoopMBB); 339*5ffd83dbSDimitry Andric } 340*5ffd83dbSDimitry Andric 341*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicBinOp( 342*5ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 343*5ffd83dbSDimitry Andric AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width, 344*5ffd83dbSDimitry Andric MachineBasicBlock::iterator &NextMBBI) { 345*5ffd83dbSDimitry Andric MachineInstr &MI = *MBBI; 346*5ffd83dbSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 347*5ffd83dbSDimitry Andric 348*5ffd83dbSDimitry Andric MachineFunction *MF = MBB.getParent(); 349*5ffd83dbSDimitry Andric auto LoopMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 350*5ffd83dbSDimitry Andric auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 351*5ffd83dbSDimitry Andric 352*5ffd83dbSDimitry Andric // Insert new MBBs. 353*5ffd83dbSDimitry Andric MF->insert(++MBB.getIterator(), LoopMBB); 354*5ffd83dbSDimitry Andric MF->insert(++LoopMBB->getIterator(), DoneMBB); 355*5ffd83dbSDimitry Andric 356*5ffd83dbSDimitry Andric // Set up successors and transfer remaining instructions to DoneMBB. 357*5ffd83dbSDimitry Andric LoopMBB->addSuccessor(LoopMBB); 358*5ffd83dbSDimitry Andric LoopMBB->addSuccessor(DoneMBB); 359*5ffd83dbSDimitry Andric DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end()); 360*5ffd83dbSDimitry Andric DoneMBB->transferSuccessors(&MBB); 361*5ffd83dbSDimitry Andric MBB.addSuccessor(LoopMBB); 362*5ffd83dbSDimitry Andric 363*5ffd83dbSDimitry Andric if (!IsMasked) 364*5ffd83dbSDimitry Andric doAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp, Width); 365*5ffd83dbSDimitry Andric else 366*5ffd83dbSDimitry Andric doMaskedAtomicBinOpExpansion(TII, MI, DL, &MBB, LoopMBB, DoneMBB, BinOp, 367*5ffd83dbSDimitry Andric Width); 368*5ffd83dbSDimitry Andric 369*5ffd83dbSDimitry Andric NextMBBI = MBB.end(); 370*5ffd83dbSDimitry Andric MI.eraseFromParent(); 371*5ffd83dbSDimitry Andric 372*5ffd83dbSDimitry Andric LivePhysRegs LiveRegs; 373*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *LoopMBB); 374*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *DoneMBB); 375*5ffd83dbSDimitry Andric 376*5ffd83dbSDimitry Andric return true; 377*5ffd83dbSDimitry Andric } 378*5ffd83dbSDimitry Andric 379*5ffd83dbSDimitry Andric static void insertSext(const RISCVInstrInfo *TII, DebugLoc DL, 380*5ffd83dbSDimitry Andric MachineBasicBlock *MBB, Register ValReg, 381*5ffd83dbSDimitry Andric Register ShamtReg) { 382*5ffd83dbSDimitry Andric BuildMI(MBB, DL, TII->get(RISCV::SLL), ValReg) 383*5ffd83dbSDimitry Andric .addReg(ValReg) 384*5ffd83dbSDimitry Andric .addReg(ShamtReg); 385*5ffd83dbSDimitry Andric BuildMI(MBB, DL, TII->get(RISCV::SRA), ValReg) 386*5ffd83dbSDimitry Andric .addReg(ValReg) 387*5ffd83dbSDimitry Andric .addReg(ShamtReg); 388*5ffd83dbSDimitry Andric } 389*5ffd83dbSDimitry Andric 390*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicMinMaxOp( 391*5ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 392*5ffd83dbSDimitry Andric AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width, 393*5ffd83dbSDimitry Andric MachineBasicBlock::iterator &NextMBBI) { 394*5ffd83dbSDimitry Andric assert(IsMasked == true && 395*5ffd83dbSDimitry Andric "Should only need to expand masked atomic max/min"); 396*5ffd83dbSDimitry Andric assert(Width == 32 && "Should never need to expand masked 64-bit operations"); 397*5ffd83dbSDimitry Andric 398*5ffd83dbSDimitry Andric MachineInstr &MI = *MBBI; 399*5ffd83dbSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 400*5ffd83dbSDimitry Andric MachineFunction *MF = MBB.getParent(); 401*5ffd83dbSDimitry Andric auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 402*5ffd83dbSDimitry Andric auto LoopIfBodyMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 403*5ffd83dbSDimitry Andric auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 404*5ffd83dbSDimitry Andric auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 405*5ffd83dbSDimitry Andric 406*5ffd83dbSDimitry Andric // Insert new MBBs. 407*5ffd83dbSDimitry Andric MF->insert(++MBB.getIterator(), LoopHeadMBB); 408*5ffd83dbSDimitry Andric MF->insert(++LoopHeadMBB->getIterator(), LoopIfBodyMBB); 409*5ffd83dbSDimitry Andric MF->insert(++LoopIfBodyMBB->getIterator(), LoopTailMBB); 410*5ffd83dbSDimitry Andric MF->insert(++LoopTailMBB->getIterator(), DoneMBB); 411*5ffd83dbSDimitry Andric 412*5ffd83dbSDimitry Andric // Set up successors and transfer remaining instructions to DoneMBB. 413*5ffd83dbSDimitry Andric LoopHeadMBB->addSuccessor(LoopIfBodyMBB); 414*5ffd83dbSDimitry Andric LoopHeadMBB->addSuccessor(LoopTailMBB); 415*5ffd83dbSDimitry Andric LoopIfBodyMBB->addSuccessor(LoopTailMBB); 416*5ffd83dbSDimitry Andric LoopTailMBB->addSuccessor(LoopHeadMBB); 417*5ffd83dbSDimitry Andric LoopTailMBB->addSuccessor(DoneMBB); 418*5ffd83dbSDimitry Andric DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end()); 419*5ffd83dbSDimitry Andric DoneMBB->transferSuccessors(&MBB); 420*5ffd83dbSDimitry Andric MBB.addSuccessor(LoopHeadMBB); 421*5ffd83dbSDimitry Andric 422*5ffd83dbSDimitry Andric Register DestReg = MI.getOperand(0).getReg(); 423*5ffd83dbSDimitry Andric Register Scratch1Reg = MI.getOperand(1).getReg(); 424*5ffd83dbSDimitry Andric Register Scratch2Reg = MI.getOperand(2).getReg(); 425*5ffd83dbSDimitry Andric Register AddrReg = MI.getOperand(3).getReg(); 426*5ffd83dbSDimitry Andric Register IncrReg = MI.getOperand(4).getReg(); 427*5ffd83dbSDimitry Andric Register MaskReg = MI.getOperand(5).getReg(); 428*5ffd83dbSDimitry Andric bool IsSigned = BinOp == AtomicRMWInst::Min || BinOp == AtomicRMWInst::Max; 429*5ffd83dbSDimitry Andric AtomicOrdering Ordering = 430*5ffd83dbSDimitry Andric static_cast<AtomicOrdering>(MI.getOperand(IsSigned ? 7 : 6).getImm()); 431*5ffd83dbSDimitry Andric 432*5ffd83dbSDimitry Andric // 433*5ffd83dbSDimitry Andric // .loophead: 434*5ffd83dbSDimitry Andric // lr.w destreg, (alignedaddr) 435*5ffd83dbSDimitry Andric // and scratch2, destreg, mask 436*5ffd83dbSDimitry Andric // mv scratch1, destreg 437*5ffd83dbSDimitry Andric // [sext scratch2 if signed min/max] 438*5ffd83dbSDimitry Andric // ifnochangeneeded scratch2, incr, .looptail 439*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg) 440*5ffd83dbSDimitry Andric .addReg(AddrReg); 441*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), Scratch2Reg) 442*5ffd83dbSDimitry Andric .addReg(DestReg) 443*5ffd83dbSDimitry Andric .addReg(MaskReg); 444*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::ADDI), Scratch1Reg) 445*5ffd83dbSDimitry Andric .addReg(DestReg) 446*5ffd83dbSDimitry Andric .addImm(0); 447*5ffd83dbSDimitry Andric 448*5ffd83dbSDimitry Andric switch (BinOp) { 449*5ffd83dbSDimitry Andric default: 450*5ffd83dbSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 451*5ffd83dbSDimitry Andric case AtomicRMWInst::Max: { 452*5ffd83dbSDimitry Andric insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg()); 453*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE)) 454*5ffd83dbSDimitry Andric .addReg(Scratch2Reg) 455*5ffd83dbSDimitry Andric .addReg(IncrReg) 456*5ffd83dbSDimitry Andric .addMBB(LoopTailMBB); 457*5ffd83dbSDimitry Andric break; 458*5ffd83dbSDimitry Andric } 459*5ffd83dbSDimitry Andric case AtomicRMWInst::Min: { 460*5ffd83dbSDimitry Andric insertSext(TII, DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg()); 461*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE)) 462*5ffd83dbSDimitry Andric .addReg(IncrReg) 463*5ffd83dbSDimitry Andric .addReg(Scratch2Reg) 464*5ffd83dbSDimitry Andric .addMBB(LoopTailMBB); 465*5ffd83dbSDimitry Andric break; 466*5ffd83dbSDimitry Andric } 467*5ffd83dbSDimitry Andric case AtomicRMWInst::UMax: 468*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU)) 469*5ffd83dbSDimitry Andric .addReg(Scratch2Reg) 470*5ffd83dbSDimitry Andric .addReg(IncrReg) 471*5ffd83dbSDimitry Andric .addMBB(LoopTailMBB); 472*5ffd83dbSDimitry Andric break; 473*5ffd83dbSDimitry Andric case AtomicRMWInst::UMin: 474*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU)) 475*5ffd83dbSDimitry Andric .addReg(IncrReg) 476*5ffd83dbSDimitry Andric .addReg(Scratch2Reg) 477*5ffd83dbSDimitry Andric .addMBB(LoopTailMBB); 478*5ffd83dbSDimitry Andric break; 479*5ffd83dbSDimitry Andric } 480*5ffd83dbSDimitry Andric 481*5ffd83dbSDimitry Andric // .loopifbody: 482*5ffd83dbSDimitry Andric // xor scratch1, destreg, incr 483*5ffd83dbSDimitry Andric // and scratch1, scratch1, mask 484*5ffd83dbSDimitry Andric // xor scratch1, destreg, scratch1 485*5ffd83dbSDimitry Andric insertMaskedMerge(TII, DL, LoopIfBodyMBB, Scratch1Reg, DestReg, IncrReg, 486*5ffd83dbSDimitry Andric MaskReg, Scratch1Reg); 487*5ffd83dbSDimitry Andric 488*5ffd83dbSDimitry Andric // .looptail: 489*5ffd83dbSDimitry Andric // sc.w scratch1, scratch1, (addr) 490*5ffd83dbSDimitry Andric // bnez scratch1, loop 491*5ffd83dbSDimitry Andric BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), Scratch1Reg) 492*5ffd83dbSDimitry Andric .addReg(AddrReg) 493*5ffd83dbSDimitry Andric .addReg(Scratch1Reg); 494*5ffd83dbSDimitry Andric BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE)) 495*5ffd83dbSDimitry Andric .addReg(Scratch1Reg) 496*5ffd83dbSDimitry Andric .addReg(RISCV::X0) 497*5ffd83dbSDimitry Andric .addMBB(LoopHeadMBB); 498*5ffd83dbSDimitry Andric 499*5ffd83dbSDimitry Andric NextMBBI = MBB.end(); 500*5ffd83dbSDimitry Andric MI.eraseFromParent(); 501*5ffd83dbSDimitry Andric 502*5ffd83dbSDimitry Andric LivePhysRegs LiveRegs; 503*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *LoopHeadMBB); 504*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *LoopIfBodyMBB); 505*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *LoopTailMBB); 506*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *DoneMBB); 507*5ffd83dbSDimitry Andric 508*5ffd83dbSDimitry Andric return true; 509*5ffd83dbSDimitry Andric } 510*5ffd83dbSDimitry Andric 511*5ffd83dbSDimitry Andric bool RISCVExpandAtomicPseudo::expandAtomicCmpXchg( 512*5ffd83dbSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked, 513*5ffd83dbSDimitry Andric int Width, MachineBasicBlock::iterator &NextMBBI) { 514*5ffd83dbSDimitry Andric MachineInstr &MI = *MBBI; 515*5ffd83dbSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 516*5ffd83dbSDimitry Andric MachineFunction *MF = MBB.getParent(); 517*5ffd83dbSDimitry Andric auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 518*5ffd83dbSDimitry Andric auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 519*5ffd83dbSDimitry Andric auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); 520*5ffd83dbSDimitry Andric 521*5ffd83dbSDimitry Andric // Insert new MBBs. 522*5ffd83dbSDimitry Andric MF->insert(++MBB.getIterator(), LoopHeadMBB); 523*5ffd83dbSDimitry Andric MF->insert(++LoopHeadMBB->getIterator(), LoopTailMBB); 524*5ffd83dbSDimitry Andric MF->insert(++LoopTailMBB->getIterator(), DoneMBB); 525*5ffd83dbSDimitry Andric 526*5ffd83dbSDimitry Andric // Set up successors and transfer remaining instructions to DoneMBB. 527*5ffd83dbSDimitry Andric LoopHeadMBB->addSuccessor(LoopTailMBB); 528*5ffd83dbSDimitry Andric LoopHeadMBB->addSuccessor(DoneMBB); 529*5ffd83dbSDimitry Andric LoopTailMBB->addSuccessor(DoneMBB); 530*5ffd83dbSDimitry Andric LoopTailMBB->addSuccessor(LoopHeadMBB); 531*5ffd83dbSDimitry Andric DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end()); 532*5ffd83dbSDimitry Andric DoneMBB->transferSuccessors(&MBB); 533*5ffd83dbSDimitry Andric MBB.addSuccessor(LoopHeadMBB); 534*5ffd83dbSDimitry Andric 535*5ffd83dbSDimitry Andric Register DestReg = MI.getOperand(0).getReg(); 536*5ffd83dbSDimitry Andric Register ScratchReg = MI.getOperand(1).getReg(); 537*5ffd83dbSDimitry Andric Register AddrReg = MI.getOperand(2).getReg(); 538*5ffd83dbSDimitry Andric Register CmpValReg = MI.getOperand(3).getReg(); 539*5ffd83dbSDimitry Andric Register NewValReg = MI.getOperand(4).getReg(); 540*5ffd83dbSDimitry Andric AtomicOrdering Ordering = 541*5ffd83dbSDimitry Andric static_cast<AtomicOrdering>(MI.getOperand(IsMasked ? 6 : 5).getImm()); 542*5ffd83dbSDimitry Andric 543*5ffd83dbSDimitry Andric if (!IsMasked) { 544*5ffd83dbSDimitry Andric // .loophead: 545*5ffd83dbSDimitry Andric // lr.[w|d] dest, (addr) 546*5ffd83dbSDimitry Andric // bne dest, cmpval, done 547*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg) 548*5ffd83dbSDimitry Andric .addReg(AddrReg); 549*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE)) 550*5ffd83dbSDimitry Andric .addReg(DestReg) 551*5ffd83dbSDimitry Andric .addReg(CmpValReg) 552*5ffd83dbSDimitry Andric .addMBB(DoneMBB); 553*5ffd83dbSDimitry Andric // .looptail: 554*5ffd83dbSDimitry Andric // sc.[w|d] scratch, newval, (addr) 555*5ffd83dbSDimitry Andric // bnez scratch, loophead 556*5ffd83dbSDimitry Andric BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg) 557*5ffd83dbSDimitry Andric .addReg(AddrReg) 558*5ffd83dbSDimitry Andric .addReg(NewValReg); 559*5ffd83dbSDimitry Andric BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE)) 560*5ffd83dbSDimitry Andric .addReg(ScratchReg) 561*5ffd83dbSDimitry Andric .addReg(RISCV::X0) 562*5ffd83dbSDimitry Andric .addMBB(LoopHeadMBB); 563*5ffd83dbSDimitry Andric } else { 564*5ffd83dbSDimitry Andric // .loophead: 565*5ffd83dbSDimitry Andric // lr.w dest, (addr) 566*5ffd83dbSDimitry Andric // and scratch, dest, mask 567*5ffd83dbSDimitry Andric // bne scratch, cmpval, done 568*5ffd83dbSDimitry Andric Register MaskReg = MI.getOperand(5).getReg(); 569*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg) 570*5ffd83dbSDimitry Andric .addReg(AddrReg); 571*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), ScratchReg) 572*5ffd83dbSDimitry Andric .addReg(DestReg) 573*5ffd83dbSDimitry Andric .addReg(MaskReg); 574*5ffd83dbSDimitry Andric BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE)) 575*5ffd83dbSDimitry Andric .addReg(ScratchReg) 576*5ffd83dbSDimitry Andric .addReg(CmpValReg) 577*5ffd83dbSDimitry Andric .addMBB(DoneMBB); 578*5ffd83dbSDimitry Andric 579*5ffd83dbSDimitry Andric // .looptail: 580*5ffd83dbSDimitry Andric // xor scratch, dest, newval 581*5ffd83dbSDimitry Andric // and scratch, scratch, mask 582*5ffd83dbSDimitry Andric // xor scratch, dest, scratch 583*5ffd83dbSDimitry Andric // sc.w scratch, scratch, (adrr) 584*5ffd83dbSDimitry Andric // bnez scratch, loophead 585*5ffd83dbSDimitry Andric insertMaskedMerge(TII, DL, LoopTailMBB, ScratchReg, DestReg, NewValReg, 586*5ffd83dbSDimitry Andric MaskReg, ScratchReg); 587*5ffd83dbSDimitry Andric BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg) 588*5ffd83dbSDimitry Andric .addReg(AddrReg) 589*5ffd83dbSDimitry Andric .addReg(ScratchReg); 590*5ffd83dbSDimitry Andric BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE)) 591*5ffd83dbSDimitry Andric .addReg(ScratchReg) 592*5ffd83dbSDimitry Andric .addReg(RISCV::X0) 593*5ffd83dbSDimitry Andric .addMBB(LoopHeadMBB); 594*5ffd83dbSDimitry Andric } 595*5ffd83dbSDimitry Andric 596*5ffd83dbSDimitry Andric NextMBBI = MBB.end(); 597*5ffd83dbSDimitry Andric MI.eraseFromParent(); 598*5ffd83dbSDimitry Andric 599*5ffd83dbSDimitry Andric LivePhysRegs LiveRegs; 600*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *LoopHeadMBB); 601*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *LoopTailMBB); 602*5ffd83dbSDimitry Andric computeAndAddLiveIns(LiveRegs, *DoneMBB); 603*5ffd83dbSDimitry Andric 604*5ffd83dbSDimitry Andric return true; 605*5ffd83dbSDimitry Andric } 606*5ffd83dbSDimitry Andric 607*5ffd83dbSDimitry Andric } // end of anonymous namespace 608*5ffd83dbSDimitry Andric 609*5ffd83dbSDimitry Andric INITIALIZE_PASS(RISCVExpandAtomicPseudo, "riscv-expand-atomic-pseudo", 610*5ffd83dbSDimitry Andric RISCV_EXPAND_ATOMIC_PSEUDO_NAME, false, false) 611*5ffd83dbSDimitry Andric 612*5ffd83dbSDimitry Andric namespace llvm { 613*5ffd83dbSDimitry Andric 614*5ffd83dbSDimitry Andric FunctionPass *createRISCVExpandAtomicPseudoPass() { 615*5ffd83dbSDimitry Andric return new RISCVExpandAtomicPseudo(); 616*5ffd83dbSDimitry Andric } 617*5ffd83dbSDimitry Andric 618*5ffd83dbSDimitry Andric } // end of namespace llvm 619