|  | //===-- PPCExpandAtomicPseudoInsts.cpp - Expand atomic pseudo instrs. -----===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains a pass that expands atomic pseudo instructions into | 
|  | // target instructions post RA. With such method, LL/SC loop is considered as | 
|  | // a whole blob and make spilling unlikely happens in the LL/SC loop. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "MCTargetDesc/PPCPredicates.h" | 
|  | #include "PPC.h" | 
|  | #include "PPCInstrInfo.h" | 
|  | #include "PPCTargetMachine.h" | 
|  |  | 
|  | #include "llvm/CodeGen/LivePhysRegs.h" | 
|  | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "ppc-atomic-expand" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class PPCExpandAtomicPseudo : public MachineFunctionPass { | 
|  | public: | 
|  | const PPCInstrInfo *TII; | 
|  | const PPCRegisterInfo *TRI; | 
|  | static char ID; | 
|  |  | 
|  | PPCExpandAtomicPseudo() : MachineFunctionPass(ID) { | 
|  | initializePPCExpandAtomicPseudoPass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  |  | 
|  | private: | 
|  | bool expandMI(MachineBasicBlock &MBB, MachineInstr &MI, | 
|  | MachineBasicBlock::iterator &NMBBI); | 
|  | bool expandAtomicRMW128(MachineBasicBlock &MBB, MachineInstr &MI, | 
|  | MachineBasicBlock::iterator &NMBBI); | 
|  | bool expandAtomicCmpSwap128(MachineBasicBlock &MBB, MachineInstr &MI, | 
|  | MachineBasicBlock::iterator &NMBBI); | 
|  | }; | 
|  |  | 
|  | static void PairedCopy(const PPCInstrInfo *TII, MachineBasicBlock &MBB, | 
|  | MachineBasicBlock::iterator MBBI, const DebugLoc &DL, | 
|  | Register Dest0, Register Dest1, Register Src0, | 
|  | Register Src1) { | 
|  | const MCInstrDesc &OR = TII->get(PPC::OR8); | 
|  | const MCInstrDesc &XOR = TII->get(PPC::XOR8); | 
|  | if (Dest0 == Src1 && Dest1 == Src0) { | 
|  | // The most tricky case, swapping values. | 
|  | BuildMI(MBB, MBBI, DL, XOR, Dest0).addReg(Dest0).addReg(Dest1); | 
|  | BuildMI(MBB, MBBI, DL, XOR, Dest1).addReg(Dest0).addReg(Dest1); | 
|  | BuildMI(MBB, MBBI, DL, XOR, Dest0).addReg(Dest0).addReg(Dest1); | 
|  | } else if (Dest0 != Src0 || Dest1 != Src1) { | 
|  | if (Dest0 == Src1 || Dest1 != Src0) { | 
|  | BuildMI(MBB, MBBI, DL, OR, Dest1).addReg(Src1).addReg(Src1); | 
|  | BuildMI(MBB, MBBI, DL, OR, Dest0).addReg(Src0).addReg(Src0); | 
|  | } else { | 
|  | BuildMI(MBB, MBBI, DL, OR, Dest0).addReg(Src0).addReg(Src0); | 
|  | BuildMI(MBB, MBBI, DL, OR, Dest1).addReg(Src1).addReg(Src1); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool PPCExpandAtomicPseudo::runOnMachineFunction(MachineFunction &MF) { | 
|  | bool Changed = false; | 
|  | TII = static_cast<const PPCInstrInfo *>(MF.getSubtarget().getInstrInfo()); | 
|  | TRI = &TII->getRegisterInfo(); | 
|  | for (MachineBasicBlock &MBB : MF) { | 
|  | for (MachineBasicBlock::iterator MBBI = MBB.begin(), MBBE = MBB.end(); | 
|  | MBBI != MBBE;) { | 
|  | MachineInstr &MI = *MBBI; | 
|  | MachineBasicBlock::iterator NMBBI = std::next(MBBI); | 
|  | Changed |= expandMI(MBB, MI, NMBBI); | 
|  | MBBI = NMBBI; | 
|  | } | 
|  | } | 
|  | if (Changed) | 
|  | MF.RenumberBlocks(); | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | bool PPCExpandAtomicPseudo::expandMI(MachineBasicBlock &MBB, MachineInstr &MI, | 
|  | MachineBasicBlock::iterator &NMBBI) { | 
|  | switch (MI.getOpcode()) { | 
|  | case PPC::ATOMIC_SWAP_I128: | 
|  | case PPC::ATOMIC_LOAD_ADD_I128: | 
|  | case PPC::ATOMIC_LOAD_SUB_I128: | 
|  | case PPC::ATOMIC_LOAD_XOR_I128: | 
|  | case PPC::ATOMIC_LOAD_NAND_I128: | 
|  | case PPC::ATOMIC_LOAD_AND_I128: | 
|  | case PPC::ATOMIC_LOAD_OR_I128: | 
|  | return expandAtomicRMW128(MBB, MI, NMBBI); | 
|  | case PPC::ATOMIC_CMP_SWAP_I128: | 
|  | return expandAtomicCmpSwap128(MBB, MI, NMBBI); | 
|  | case PPC::BUILD_QUADWORD: { | 
|  | Register Dst = MI.getOperand(0).getReg(); | 
|  | Register DstHi = TRI->getSubReg(Dst, PPC::sub_gp8_x0); | 
|  | Register DstLo = TRI->getSubReg(Dst, PPC::sub_gp8_x1); | 
|  | Register Lo = MI.getOperand(1).getReg(); | 
|  | Register Hi = MI.getOperand(2).getReg(); | 
|  | PairedCopy(TII, MBB, MI, MI.getDebugLoc(), DstHi, DstLo, Hi, Lo); | 
|  | MI.eraseFromParent(); | 
|  | return true; | 
|  | } | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool PPCExpandAtomicPseudo::expandAtomicRMW128( | 
|  | MachineBasicBlock &MBB, MachineInstr &MI, | 
|  | MachineBasicBlock::iterator &NMBBI) { | 
|  | const MCInstrDesc &LL = TII->get(PPC::LQARX); | 
|  | const MCInstrDesc &SC = TII->get(PPC::STQCX); | 
|  | DebugLoc DL = MI.getDebugLoc(); | 
|  | MachineFunction *MF = MBB.getParent(); | 
|  | const BasicBlock *BB = MBB.getBasicBlock(); | 
|  | // Create layout of control flow. | 
|  | MachineFunction::iterator MFI = ++MBB.getIterator(); | 
|  | MachineBasicBlock *LoopMBB = MF->CreateMachineBasicBlock(BB); | 
|  | MachineBasicBlock *ExitMBB = MF->CreateMachineBasicBlock(BB); | 
|  | MF->insert(MFI, LoopMBB); | 
|  | MF->insert(MFI, ExitMBB); | 
|  | ExitMBB->splice(ExitMBB->begin(), &MBB, std::next(MI.getIterator()), | 
|  | MBB.end()); | 
|  | ExitMBB->transferSuccessorsAndUpdatePHIs(&MBB); | 
|  | MBB.addSuccessor(LoopMBB); | 
|  |  | 
|  | // For non-min/max operations, control flow is kinda like: | 
|  | // MBB: | 
|  | //   ... | 
|  | // LoopMBB: | 
|  | //   lqarx in, ptr | 
|  | //   addc out.sub_x1, in.sub_x1, op.sub_x1 | 
|  | //   adde out.sub_x0, in.sub_x0, op.sub_x0 | 
|  | //   stqcx out, ptr | 
|  | //   bne- LoopMBB | 
|  | // ExitMBB: | 
|  | //   ... | 
|  | Register Old = MI.getOperand(0).getReg(); | 
|  | Register OldHi = TRI->getSubReg(Old, PPC::sub_gp8_x0); | 
|  | Register OldLo = TRI->getSubReg(Old, PPC::sub_gp8_x1); | 
|  | Register Scratch = MI.getOperand(1).getReg(); | 
|  | Register ScratchHi = TRI->getSubReg(Scratch, PPC::sub_gp8_x0); | 
|  | Register ScratchLo = TRI->getSubReg(Scratch, PPC::sub_gp8_x1); | 
|  | Register RA = MI.getOperand(2).getReg(); | 
|  | Register RB = MI.getOperand(3).getReg(); | 
|  | Register IncrLo = MI.getOperand(4).getReg(); | 
|  | Register IncrHi = MI.getOperand(5).getReg(); | 
|  | unsigned RMWOpcode = MI.getOpcode(); | 
|  |  | 
|  | MachineBasicBlock *CurrentMBB = LoopMBB; | 
|  | BuildMI(CurrentMBB, DL, LL, Old).addReg(RA).addReg(RB); | 
|  |  | 
|  | switch (RMWOpcode) { | 
|  | case PPC::ATOMIC_SWAP_I128: | 
|  | PairedCopy(TII, *CurrentMBB, CurrentMBB->end(), DL, ScratchHi, ScratchLo, | 
|  | IncrHi, IncrLo); | 
|  | break; | 
|  | case PPC::ATOMIC_LOAD_ADD_I128: | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::ADDC8), ScratchLo) | 
|  | .addReg(IncrLo) | 
|  | .addReg(OldLo); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::ADDE8), ScratchHi) | 
|  | .addReg(IncrHi) | 
|  | .addReg(OldHi); | 
|  | break; | 
|  | case PPC::ATOMIC_LOAD_SUB_I128: | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::SUBFC8), ScratchLo) | 
|  | .addReg(IncrLo) | 
|  | .addReg(OldLo); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::SUBFE8), ScratchHi) | 
|  | .addReg(IncrHi) | 
|  | .addReg(OldHi); | 
|  | break; | 
|  |  | 
|  | #define TRIVIAL_ATOMICRMW(Opcode, Instr)                                       \ | 
|  | case Opcode:                                                                 \ | 
|  | BuildMI(CurrentMBB, DL, TII->get((Instr)), ScratchLo)                      \ | 
|  | .addReg(IncrLo)                                                        \ | 
|  | .addReg(OldLo);                                                        \ | 
|  | BuildMI(CurrentMBB, DL, TII->get((Instr)), ScratchHi)                      \ | 
|  | .addReg(IncrHi)                                                        \ | 
|  | .addReg(OldHi);                                                        \ | 
|  | break | 
|  |  | 
|  | TRIVIAL_ATOMICRMW(PPC::ATOMIC_LOAD_OR_I128, PPC::OR8); | 
|  | TRIVIAL_ATOMICRMW(PPC::ATOMIC_LOAD_XOR_I128, PPC::XOR8); | 
|  | TRIVIAL_ATOMICRMW(PPC::ATOMIC_LOAD_AND_I128, PPC::AND8); | 
|  | TRIVIAL_ATOMICRMW(PPC::ATOMIC_LOAD_NAND_I128, PPC::NAND8); | 
|  | #undef TRIVIAL_ATOMICRMW | 
|  | default: | 
|  | llvm_unreachable("Unhandled atomic RMW operation"); | 
|  | } | 
|  | BuildMI(CurrentMBB, DL, SC).addReg(Scratch).addReg(RA).addReg(RB); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::BCC)) | 
|  | .addImm(PPC::PRED_NE) | 
|  | .addReg(PPC::CR0) | 
|  | .addMBB(LoopMBB); | 
|  | CurrentMBB->addSuccessor(LoopMBB); | 
|  | CurrentMBB->addSuccessor(ExitMBB); | 
|  | recomputeLiveIns(*LoopMBB); | 
|  | recomputeLiveIns(*ExitMBB); | 
|  | NMBBI = MBB.end(); | 
|  | MI.eraseFromParent(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool PPCExpandAtomicPseudo::expandAtomicCmpSwap128( | 
|  | MachineBasicBlock &MBB, MachineInstr &MI, | 
|  | MachineBasicBlock::iterator &NMBBI) { | 
|  | const MCInstrDesc &LL = TII->get(PPC::LQARX); | 
|  | const MCInstrDesc &SC = TII->get(PPC::STQCX); | 
|  | DebugLoc DL = MI.getDebugLoc(); | 
|  | MachineFunction *MF = MBB.getParent(); | 
|  | const BasicBlock *BB = MBB.getBasicBlock(); | 
|  | Register Old = MI.getOperand(0).getReg(); | 
|  | Register OldHi = TRI->getSubReg(Old, PPC::sub_gp8_x0); | 
|  | Register OldLo = TRI->getSubReg(Old, PPC::sub_gp8_x1); | 
|  | Register Scratch = MI.getOperand(1).getReg(); | 
|  | Register ScratchHi = TRI->getSubReg(Scratch, PPC::sub_gp8_x0); | 
|  | Register ScratchLo = TRI->getSubReg(Scratch, PPC::sub_gp8_x1); | 
|  | Register RA = MI.getOperand(2).getReg(); | 
|  | Register RB = MI.getOperand(3).getReg(); | 
|  | Register CmpLo = MI.getOperand(4).getReg(); | 
|  | Register CmpHi = MI.getOperand(5).getReg(); | 
|  | Register NewLo = MI.getOperand(6).getReg(); | 
|  | Register NewHi = MI.getOperand(7).getReg(); | 
|  | // Create layout of control flow. | 
|  | // loop: | 
|  | //   old = lqarx ptr | 
|  | //   <compare old, cmp> | 
|  | //   bne 0, fail | 
|  | // succ: | 
|  | //   stqcx new ptr | 
|  | //   bne 0, loop | 
|  | //   b exit | 
|  | // fail: | 
|  | //   stqcx old ptr | 
|  | // exit: | 
|  | //   .... | 
|  | MachineFunction::iterator MFI = ++MBB.getIterator(); | 
|  | MachineBasicBlock *LoopCmpMBB = MF->CreateMachineBasicBlock(BB); | 
|  | MachineBasicBlock *CmpSuccMBB = MF->CreateMachineBasicBlock(BB); | 
|  | MachineBasicBlock *CmpFailMBB = MF->CreateMachineBasicBlock(BB); | 
|  | MachineBasicBlock *ExitMBB = MF->CreateMachineBasicBlock(BB); | 
|  | MF->insert(MFI, LoopCmpMBB); | 
|  | MF->insert(MFI, CmpSuccMBB); | 
|  | MF->insert(MFI, CmpFailMBB); | 
|  | MF->insert(MFI, ExitMBB); | 
|  | ExitMBB->splice(ExitMBB->begin(), &MBB, std::next(MI.getIterator()), | 
|  | MBB.end()); | 
|  | ExitMBB->transferSuccessorsAndUpdatePHIs(&MBB); | 
|  | MBB.addSuccessor(LoopCmpMBB); | 
|  | // Build loop. | 
|  | MachineBasicBlock *CurrentMBB = LoopCmpMBB; | 
|  | BuildMI(CurrentMBB, DL, LL, Old).addReg(RA).addReg(RB); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::XOR8), ScratchLo) | 
|  | .addReg(OldLo) | 
|  | .addReg(CmpLo); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::XOR8), ScratchHi) | 
|  | .addReg(OldHi) | 
|  | .addReg(CmpHi); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::OR8_rec), ScratchLo) | 
|  | .addReg(ScratchLo) | 
|  | .addReg(ScratchHi); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::BCC)) | 
|  | .addImm(PPC::PRED_NE) | 
|  | .addReg(PPC::CR0) | 
|  | .addMBB(CmpFailMBB); | 
|  | CurrentMBB->addSuccessor(CmpSuccMBB); | 
|  | CurrentMBB->addSuccessor(CmpFailMBB); | 
|  | // Build succ. | 
|  | CurrentMBB = CmpSuccMBB; | 
|  | PairedCopy(TII, *CurrentMBB, CurrentMBB->end(), DL, ScratchHi, ScratchLo, | 
|  | NewHi, NewLo); | 
|  | BuildMI(CurrentMBB, DL, SC).addReg(Scratch).addReg(RA).addReg(RB); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::BCC)) | 
|  | .addImm(PPC::PRED_NE) | 
|  | .addReg(PPC::CR0) | 
|  | .addMBB(LoopCmpMBB); | 
|  | BuildMI(CurrentMBB, DL, TII->get(PPC::B)).addMBB(ExitMBB); | 
|  | CurrentMBB->addSuccessor(LoopCmpMBB); | 
|  | CurrentMBB->addSuccessor(ExitMBB); | 
|  | CurrentMBB = CmpFailMBB; | 
|  | BuildMI(CurrentMBB, DL, SC).addReg(Old).addReg(RA).addReg(RB); | 
|  | CurrentMBB->addSuccessor(ExitMBB); | 
|  |  | 
|  | recomputeLiveIns(*LoopCmpMBB); | 
|  | recomputeLiveIns(*CmpSuccMBB); | 
|  | recomputeLiveIns(*CmpFailMBB); | 
|  | recomputeLiveIns(*ExitMBB); | 
|  | NMBBI = MBB.end(); | 
|  | MI.eraseFromParent(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | INITIALIZE_PASS(PPCExpandAtomicPseudo, DEBUG_TYPE, "PowerPC Expand Atomic", | 
|  | false, false) | 
|  |  | 
|  | char PPCExpandAtomicPseudo::ID = 0; | 
|  | FunctionPass *llvm::createPPCExpandAtomicPseudoPass() { | 
|  | return new PPCExpandAtomicPseudo(); | 
|  | } |