15ffd83dbSDimitry Andric //===-- SIPostRABundler.cpp -----------------------------------------------===// 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 /// \file 105ffd83dbSDimitry Andric /// This pass creates bundles of memory instructions to protect adjacent loads 11*349cc55cSDimitry Andric /// and stores from being rescheduled apart from each other post-RA. 125ffd83dbSDimitry Andric /// 135ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 145ffd83dbSDimitry Andric 155ffd83dbSDimitry Andric #include "AMDGPU.h" 16e8d8bef9SDimitry Andric #include "GCNSubtarget.h" 175ffd83dbSDimitry Andric #include "llvm/ADT/SmallSet.h" 185ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 195ffd83dbSDimitry Andric 205ffd83dbSDimitry Andric using namespace llvm; 215ffd83dbSDimitry Andric 225ffd83dbSDimitry Andric #define DEBUG_TYPE "si-post-ra-bundler" 235ffd83dbSDimitry Andric 245ffd83dbSDimitry Andric namespace { 255ffd83dbSDimitry Andric 265ffd83dbSDimitry Andric class SIPostRABundler : public MachineFunctionPass { 275ffd83dbSDimitry Andric public: 285ffd83dbSDimitry Andric static char ID; 295ffd83dbSDimitry Andric 305ffd83dbSDimitry Andric public: 315ffd83dbSDimitry Andric SIPostRABundler() : MachineFunctionPass(ID) { 325ffd83dbSDimitry Andric initializeSIPostRABundlerPass(*PassRegistry::getPassRegistry()); 335ffd83dbSDimitry Andric } 345ffd83dbSDimitry Andric 355ffd83dbSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 365ffd83dbSDimitry Andric 375ffd83dbSDimitry Andric StringRef getPassName() const override { 385ffd83dbSDimitry Andric return "SI post-RA bundler"; 395ffd83dbSDimitry Andric } 405ffd83dbSDimitry Andric 415ffd83dbSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 425ffd83dbSDimitry Andric AU.setPreservesAll(); 435ffd83dbSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 445ffd83dbSDimitry Andric } 455ffd83dbSDimitry Andric 465ffd83dbSDimitry Andric private: 475ffd83dbSDimitry Andric const SIRegisterInfo *TRI; 485ffd83dbSDimitry Andric 495ffd83dbSDimitry Andric SmallSet<Register, 16> Defs; 505ffd83dbSDimitry Andric 51fe6060f1SDimitry Andric void collectUsedRegUnits(const MachineInstr &MI, 52fe6060f1SDimitry Andric BitVector &UsedRegUnits) const; 535ffd83dbSDimitry Andric 54fe6060f1SDimitry Andric bool isBundleCandidate(const MachineInstr &MI) const; 55fe6060f1SDimitry Andric bool isDependentLoad(const MachineInstr &MI) const; 56fe6060f1SDimitry Andric bool canBundle(const MachineInstr &MI, const MachineInstr &NextMI) const; 575ffd83dbSDimitry Andric }; 585ffd83dbSDimitry Andric 59fe6060f1SDimitry Andric constexpr uint64_t MemFlags = SIInstrFlags::MTBUF | SIInstrFlags::MUBUF | 60fe6060f1SDimitry Andric SIInstrFlags::SMRD | SIInstrFlags::DS | 61fe6060f1SDimitry Andric SIInstrFlags::FLAT | SIInstrFlags::MIMG; 62fe6060f1SDimitry Andric 635ffd83dbSDimitry Andric } // End anonymous namespace. 645ffd83dbSDimitry Andric 655ffd83dbSDimitry Andric INITIALIZE_PASS(SIPostRABundler, DEBUG_TYPE, "SI post-RA bundler", false, false) 665ffd83dbSDimitry Andric 675ffd83dbSDimitry Andric char SIPostRABundler::ID = 0; 685ffd83dbSDimitry Andric 695ffd83dbSDimitry Andric char &llvm::SIPostRABundlerID = SIPostRABundler::ID; 705ffd83dbSDimitry Andric 715ffd83dbSDimitry Andric FunctionPass *llvm::createSIPostRABundlerPass() { 725ffd83dbSDimitry Andric return new SIPostRABundler(); 735ffd83dbSDimitry Andric } 745ffd83dbSDimitry Andric 755ffd83dbSDimitry Andric bool SIPostRABundler::isDependentLoad(const MachineInstr &MI) const { 765ffd83dbSDimitry Andric if (!MI.mayLoad()) 775ffd83dbSDimitry Andric return false; 785ffd83dbSDimitry Andric 795ffd83dbSDimitry Andric for (const MachineOperand &Op : MI.explicit_operands()) { 805ffd83dbSDimitry Andric if (!Op.isReg()) 815ffd83dbSDimitry Andric continue; 825ffd83dbSDimitry Andric Register Reg = Op.getReg(); 835ffd83dbSDimitry Andric for (Register Def : Defs) 845ffd83dbSDimitry Andric if (TRI->regsOverlap(Reg, Def)) 855ffd83dbSDimitry Andric return true; 865ffd83dbSDimitry Andric } 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric return false; 895ffd83dbSDimitry Andric } 905ffd83dbSDimitry Andric 91fe6060f1SDimitry Andric void SIPostRABundler::collectUsedRegUnits(const MachineInstr &MI, 92fe6060f1SDimitry Andric BitVector &UsedRegUnits) const { 93*349cc55cSDimitry Andric if (MI.isDebugInstr()) 94*349cc55cSDimitry Andric return; 95*349cc55cSDimitry Andric 96fe6060f1SDimitry Andric for (const MachineOperand &Op : MI.operands()) { 97fe6060f1SDimitry Andric if (!Op.isReg() || !Op.readsReg()) 98fe6060f1SDimitry Andric continue; 99fe6060f1SDimitry Andric 100fe6060f1SDimitry Andric Register Reg = Op.getReg(); 101fe6060f1SDimitry Andric assert(!Op.getSubReg() && 102fe6060f1SDimitry Andric "subregister indexes should not be present after RA"); 103fe6060f1SDimitry Andric 104fe6060f1SDimitry Andric for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units) 105fe6060f1SDimitry Andric UsedRegUnits.set(*Units); 106fe6060f1SDimitry Andric } 107fe6060f1SDimitry Andric } 108fe6060f1SDimitry Andric 109fe6060f1SDimitry Andric bool SIPostRABundler::isBundleCandidate(const MachineInstr &MI) const { 110fe6060f1SDimitry Andric const uint64_t IMemFlags = MI.getDesc().TSFlags & MemFlags; 111fe6060f1SDimitry Andric return IMemFlags != 0 && MI.mayLoadOrStore() && !MI.isBundled(); 112fe6060f1SDimitry Andric } 113fe6060f1SDimitry Andric 114fe6060f1SDimitry Andric bool SIPostRABundler::canBundle(const MachineInstr &MI, 115fe6060f1SDimitry Andric const MachineInstr &NextMI) const { 116fe6060f1SDimitry Andric const uint64_t IMemFlags = MI.getDesc().TSFlags & MemFlags; 117fe6060f1SDimitry Andric 118fe6060f1SDimitry Andric return (IMemFlags != 0 && MI.mayLoadOrStore() && !NextMI.isBundled() && 119fe6060f1SDimitry Andric NextMI.mayLoad() == MI.mayLoad() && NextMI.mayStore() == MI.mayStore() && 120fe6060f1SDimitry Andric ((NextMI.getDesc().TSFlags & MemFlags) == IMemFlags) && 121fe6060f1SDimitry Andric !isDependentLoad(NextMI)); 122fe6060f1SDimitry Andric } 123fe6060f1SDimitry Andric 1245ffd83dbSDimitry Andric bool SIPostRABundler::runOnMachineFunction(MachineFunction &MF) { 1255ffd83dbSDimitry Andric if (skipFunction(MF.getFunction())) 1265ffd83dbSDimitry Andric return false; 1275ffd83dbSDimitry Andric 1285ffd83dbSDimitry Andric TRI = MF.getSubtarget<GCNSubtarget>().getRegisterInfo(); 129fe6060f1SDimitry Andric BitVector BundleUsedRegUnits(TRI->getNumRegUnits()); 130fe6060f1SDimitry Andric BitVector KillUsedRegUnits(TRI->getNumRegUnits()); 1315ffd83dbSDimitry Andric 132fe6060f1SDimitry Andric bool Changed = false; 1335ffd83dbSDimitry Andric for (MachineBasicBlock &MBB : MF) { 1345ffd83dbSDimitry Andric MachineBasicBlock::instr_iterator Next; 1355ffd83dbSDimitry Andric MachineBasicBlock::instr_iterator B = MBB.instr_begin(); 1365ffd83dbSDimitry Andric MachineBasicBlock::instr_iterator E = MBB.instr_end(); 137fe6060f1SDimitry Andric 1385ffd83dbSDimitry Andric for (auto I = B; I != E; I = Next) { 1395ffd83dbSDimitry Andric Next = std::next(I); 140fe6060f1SDimitry Andric if (!isBundleCandidate(*I)) 1415ffd83dbSDimitry Andric continue; 1425ffd83dbSDimitry Andric 143fe6060f1SDimitry Andric assert(Defs.empty()); 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric if (I->getNumExplicitDefs() != 0) 1465ffd83dbSDimitry Andric Defs.insert(I->defs().begin()->getReg()); 147fe6060f1SDimitry Andric 148fe6060f1SDimitry Andric MachineBasicBlock::instr_iterator BundleStart = I; 149fe6060f1SDimitry Andric MachineBasicBlock::instr_iterator BundleEnd = I; 150fe6060f1SDimitry Andric unsigned ClauseLength = 1; 151fe6060f1SDimitry Andric for (I = Next; I != E; I = Next) { 152fe6060f1SDimitry Andric Next = std::next(I); 153fe6060f1SDimitry Andric 154fe6060f1SDimitry Andric assert(BundleEnd != I); 155fe6060f1SDimitry Andric if (canBundle(*BundleEnd, *I)) { 156fe6060f1SDimitry Andric BundleEnd = I; 157fe6060f1SDimitry Andric if (I->getNumExplicitDefs() != 0) 158fe6060f1SDimitry Andric Defs.insert(I->defs().begin()->getReg()); 159fe6060f1SDimitry Andric ++ClauseLength; 160fe6060f1SDimitry Andric } else if (!I->isMetaInstruction()) { 161fe6060f1SDimitry Andric // Allow meta instructions in between bundle candidates, but do not 162fe6060f1SDimitry Andric // start or end a bundle on one. 163fe6060f1SDimitry Andric // 164fe6060f1SDimitry Andric // TODO: It may be better to move meta instructions like dbg_value 165fe6060f1SDimitry Andric // after the bundle. We're relying on the memory legalizer to unbundle 166fe6060f1SDimitry Andric // these. 167fe6060f1SDimitry Andric break; 168fe6060f1SDimitry Andric } 1695ffd83dbSDimitry Andric } 1705ffd83dbSDimitry Andric 171fe6060f1SDimitry Andric Next = std::next(BundleEnd); 172fe6060f1SDimitry Andric if (ClauseLength > 1) { 1735ffd83dbSDimitry Andric Changed = true; 174fe6060f1SDimitry Andric 175fe6060f1SDimitry Andric // Before register allocation, kills are inserted after potential soft 176fe6060f1SDimitry Andric // clauses to hint register allocation. Look for kills that look like 177fe6060f1SDimitry Andric // this, and erase them. 178fe6060f1SDimitry Andric if (Next != E && Next->isKill()) { 179fe6060f1SDimitry Andric 180fe6060f1SDimitry Andric // TODO: Should maybe back-propagate kill flags to the bundle. 181fe6060f1SDimitry Andric for (const MachineInstr &BundleMI : make_range(BundleStart, Next)) 182fe6060f1SDimitry Andric collectUsedRegUnits(BundleMI, BundleUsedRegUnits); 183fe6060f1SDimitry Andric 184fe6060f1SDimitry Andric BundleUsedRegUnits.flip(); 185fe6060f1SDimitry Andric 186fe6060f1SDimitry Andric while (Next != E && Next->isKill()) { 187fe6060f1SDimitry Andric MachineInstr &Kill = *Next; 188fe6060f1SDimitry Andric collectUsedRegUnits(Kill, KillUsedRegUnits); 189fe6060f1SDimitry Andric 190fe6060f1SDimitry Andric KillUsedRegUnits &= BundleUsedRegUnits; 191fe6060f1SDimitry Andric 192fe6060f1SDimitry Andric // Erase the kill if it's a subset of the used registers. 193fe6060f1SDimitry Andric // 194fe6060f1SDimitry Andric // TODO: Should we just remove all kills? Is there any real reason to 195fe6060f1SDimitry Andric // keep them after RA? 196fe6060f1SDimitry Andric if (KillUsedRegUnits.none()) { 197fe6060f1SDimitry Andric ++Next; 198fe6060f1SDimitry Andric Kill.eraseFromParent(); 199fe6060f1SDimitry Andric } else 200fe6060f1SDimitry Andric break; 201fe6060f1SDimitry Andric 202fe6060f1SDimitry Andric KillUsedRegUnits.reset(); 203fe6060f1SDimitry Andric } 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric BundleUsedRegUnits.reset(); 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric 208fe6060f1SDimitry Andric finalizeBundle(MBB, BundleStart, Next); 2095ffd83dbSDimitry Andric } 2105ffd83dbSDimitry Andric 2115ffd83dbSDimitry Andric Defs.clear(); 2125ffd83dbSDimitry Andric } 213fe6060f1SDimitry Andric } 2145ffd83dbSDimitry Andric 2155ffd83dbSDimitry Andric return Changed; 2165ffd83dbSDimitry Andric } 217