1 //===-- SIPostRABundler.cpp -----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This pass creates bundles of memory instructions to protect adjacent loads
11 /// and stores from being rescheduled apart from each other post-RA.
13 //===----------------------------------------------------------------------===//
16 #include "GCNSubtarget.h"
17 #include "llvm/ADT/SmallSet.h"
18 #include "llvm/CodeGen/MachineFunctionPass.h"
22 #define DEBUG_TYPE "si-post-ra-bundler"
26 class SIPostRABundler
: public MachineFunctionPass
{
31 SIPostRABundler() : MachineFunctionPass(ID
) {
32 initializeSIPostRABundlerPass(*PassRegistry::getPassRegistry());
35 bool runOnMachineFunction(MachineFunction
&MF
) override
;
37 StringRef
getPassName() const override
{
38 return "SI post-RA bundler";
41 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
43 MachineFunctionPass::getAnalysisUsage(AU
);
47 const SIRegisterInfo
*TRI
;
49 SmallSet
<Register
, 16> Defs
;
51 void collectUsedRegUnits(const MachineInstr
&MI
,
52 BitVector
&UsedRegUnits
) const;
54 bool isBundleCandidate(const MachineInstr
&MI
) const;
55 bool isDependentLoad(const MachineInstr
&MI
) const;
56 bool canBundle(const MachineInstr
&MI
, const MachineInstr
&NextMI
) const;
59 constexpr uint64_t MemFlags
= SIInstrFlags::MTBUF
| SIInstrFlags::MUBUF
|
60 SIInstrFlags::SMRD
| SIInstrFlags::DS
|
61 SIInstrFlags::FLAT
| SIInstrFlags::MIMG
;
63 } // End anonymous namespace.
65 INITIALIZE_PASS(SIPostRABundler
, DEBUG_TYPE
, "SI post-RA bundler", false, false)
67 char SIPostRABundler::ID
= 0;
69 char &llvm::SIPostRABundlerID
= SIPostRABundler::ID
;
71 FunctionPass
*llvm::createSIPostRABundlerPass() {
72 return new SIPostRABundler();
75 bool SIPostRABundler::isDependentLoad(const MachineInstr
&MI
) const {
79 for (const MachineOperand
&Op
: MI
.explicit_operands()) {
82 Register Reg
= Op
.getReg();
83 for (Register Def
: Defs
)
84 if (TRI
->regsOverlap(Reg
, Def
))
91 void SIPostRABundler::collectUsedRegUnits(const MachineInstr
&MI
,
92 BitVector
&UsedRegUnits
) const {
93 if (MI
.isDebugInstr())
96 for (const MachineOperand
&Op
: MI
.operands()) {
97 if (!Op
.isReg() || !Op
.readsReg())
100 Register Reg
= Op
.getReg();
101 assert(!Op
.getSubReg() &&
102 "subregister indexes should not be present after RA");
104 for (MCRegUnit Unit
: TRI
->regunits(Reg
))
105 UsedRegUnits
.set(Unit
);
109 bool SIPostRABundler::isBundleCandidate(const MachineInstr
&MI
) const {
110 const uint64_t IMemFlags
= MI
.getDesc().TSFlags
& MemFlags
;
111 return IMemFlags
!= 0 && MI
.mayLoadOrStore() && !MI
.isBundled();
114 bool SIPostRABundler::canBundle(const MachineInstr
&MI
,
115 const MachineInstr
&NextMI
) const {
116 const uint64_t IMemFlags
= MI
.getDesc().TSFlags
& MemFlags
;
118 return (IMemFlags
!= 0 && MI
.mayLoadOrStore() && !NextMI
.isBundled() &&
119 NextMI
.mayLoad() == MI
.mayLoad() && NextMI
.mayStore() == MI
.mayStore() &&
120 ((NextMI
.getDesc().TSFlags
& MemFlags
) == IMemFlags
) &&
121 !isDependentLoad(NextMI
));
124 bool SIPostRABundler::runOnMachineFunction(MachineFunction
&MF
) {
125 if (skipFunction(MF
.getFunction()))
128 TRI
= MF
.getSubtarget
<GCNSubtarget
>().getRegisterInfo();
129 BitVector
BundleUsedRegUnits(TRI
->getNumRegUnits());
130 BitVector
KillUsedRegUnits(TRI
->getNumRegUnits());
132 bool Changed
= false;
133 for (MachineBasicBlock
&MBB
: MF
) {
134 bool HasIGLPInstrs
= llvm::any_of(MBB
.instrs(), [](MachineInstr
&MI
) {
135 unsigned Opc
= MI
.getOpcode();
136 return Opc
== AMDGPU::SCHED_GROUP_BARRIER
|| Opc
== AMDGPU::IGLP_OPT
;
139 // Don't cluster with IGLP instructions.
143 MachineBasicBlock::instr_iterator Next
;
144 MachineBasicBlock::instr_iterator B
= MBB
.instr_begin();
145 MachineBasicBlock::instr_iterator E
= MBB
.instr_end();
147 for (auto I
= B
; I
!= E
; I
= Next
) {
149 if (!isBundleCandidate(*I
))
152 assert(Defs
.empty());
154 if (I
->getNumExplicitDefs() != 0)
155 Defs
.insert(I
->defs().begin()->getReg());
157 MachineBasicBlock::instr_iterator BundleStart
= I
;
158 MachineBasicBlock::instr_iterator BundleEnd
= I
;
159 unsigned ClauseLength
= 1;
160 for (I
= Next
; I
!= E
; I
= Next
) {
163 assert(BundleEnd
!= I
);
164 if (canBundle(*BundleEnd
, *I
)) {
166 if (I
->getNumExplicitDefs() != 0)
167 Defs
.insert(I
->defs().begin()->getReg());
169 } else if (!I
->isMetaInstruction()) {
170 // Allow meta instructions in between bundle candidates, but do not
171 // start or end a bundle on one.
173 // TODO: It may be better to move meta instructions like dbg_value
174 // after the bundle. We're relying on the memory legalizer to unbundle
180 Next
= std::next(BundleEnd
);
181 if (ClauseLength
> 1) {
184 // Before register allocation, kills are inserted after potential soft
185 // clauses to hint register allocation. Look for kills that look like
186 // this, and erase them.
187 if (Next
!= E
&& Next
->isKill()) {
189 // TODO: Should maybe back-propagate kill flags to the bundle.
190 for (const MachineInstr
&BundleMI
: make_range(BundleStart
, Next
))
191 collectUsedRegUnits(BundleMI
, BundleUsedRegUnits
);
193 BundleUsedRegUnits
.flip();
195 while (Next
!= E
&& Next
->isKill()) {
196 MachineInstr
&Kill
= *Next
;
197 collectUsedRegUnits(Kill
, KillUsedRegUnits
);
199 KillUsedRegUnits
&= BundleUsedRegUnits
;
201 // Erase the kill if it's a subset of the used registers.
203 // TODO: Should we just remove all kills? Is there any real reason to
204 // keep them after RA?
205 if (KillUsedRegUnits
.none()) {
207 Kill
.eraseFromParent();
211 KillUsedRegUnits
.reset();
214 BundleUsedRegUnits
.reset();
217 finalizeBundle(MBB
, BundleStart
, Next
);