1 //===-- SIPostRABundler.cpp -----------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file
10 /// This pass creates bundles of memory instructions to protect adjacent loads
11 /// and stores from beeing rescheduled apart from each other post-RA.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "AMDGPU.h"
16 #include "GCNSubtarget.h"
17 #include "llvm/ADT/SmallSet.h"
18 #include "llvm/CodeGen/MachineFunctionPass.h"
19 
20 using namespace llvm;
21 
22 #define DEBUG_TYPE "si-post-ra-bundler"
23 
24 namespace {
25 
26 class SIPostRABundler : public MachineFunctionPass {
27 public:
28   static char ID;
29 
30 public:
31   SIPostRABundler() : MachineFunctionPass(ID) {
32     initializeSIPostRABundlerPass(*PassRegistry::getPassRegistry());
33   }
34 
35   bool runOnMachineFunction(MachineFunction &MF) override;
36 
37   StringRef getPassName() const override {
38     return "SI post-RA bundler";
39   }
40 
41   void getAnalysisUsage(AnalysisUsage &AU) const override {
42     AU.setPreservesAll();
43     MachineFunctionPass::getAnalysisUsage(AU);
44   }
45 
46 private:
47   const SIRegisterInfo *TRI;
48 
49   SmallSet<Register, 16> Defs;
50 
51   bool isDependentLoad(const MachineInstr &MI) const;
52 
53 };
54 
55 } // End anonymous namespace.
56 
57 INITIALIZE_PASS(SIPostRABundler, DEBUG_TYPE, "SI post-RA bundler", false, false)
58 
59 char SIPostRABundler::ID = 0;
60 
61 char &llvm::SIPostRABundlerID = SIPostRABundler::ID;
62 
63 FunctionPass *llvm::createSIPostRABundlerPass() {
64   return new SIPostRABundler();
65 }
66 
67 bool SIPostRABundler::isDependentLoad(const MachineInstr &MI) const {
68   if (!MI.mayLoad())
69     return false;
70 
71   for (const MachineOperand &Op : MI.explicit_operands()) {
72     if (!Op.isReg())
73       continue;
74     Register Reg = Op.getReg();
75     for (Register Def : Defs)
76       if (TRI->regsOverlap(Reg, Def))
77         return true;
78   }
79 
80   return false;
81 }
82 
83 bool SIPostRABundler::runOnMachineFunction(MachineFunction &MF) {
84   if (skipFunction(MF.getFunction()))
85     return false;
86 
87   TRI = MF.getSubtarget<GCNSubtarget>().getRegisterInfo();
88   bool Changed = false;
89   const uint64_t MemFlags = SIInstrFlags::MTBUF | SIInstrFlags::MUBUF |
90                             SIInstrFlags::SMRD | SIInstrFlags::DS |
91                             SIInstrFlags::FLAT | SIInstrFlags::MIMG;
92 
93   for (MachineBasicBlock &MBB : MF) {
94     MachineBasicBlock::instr_iterator Next;
95     MachineBasicBlock::instr_iterator B = MBB.instr_begin();
96     MachineBasicBlock::instr_iterator E = MBB.instr_end();
97     for (auto I = B; I != E; I = Next) {
98       Next = std::next(I);
99 
100       const uint64_t IMemFlags = I->getDesc().TSFlags & MemFlags;
101 
102       if (IMemFlags == 0 || I->isBundled() || !I->mayLoadOrStore() ||
103           B->mayLoad() != I->mayLoad() || B->mayStore() != I->mayStore() ||
104           ((B->getDesc().TSFlags & MemFlags) != IMemFlags) ||
105           isDependentLoad(*I)) {
106 
107         if (B != I) {
108           if (std::next(B) != I) {
109             finalizeBundle(MBB, B, I);
110             Changed = true;
111           }
112           Next = I;
113         }
114 
115         B = Next;
116         Defs.clear();
117         continue;
118       }
119 
120       if (I->getNumExplicitDefs() == 0)
121         continue;
122 
123       Defs.insert(I->defs().begin()->getReg());
124     }
125 
126     if (B != E && std::next(B) != E) {
127       finalizeBundle(MBB, B, E);
128       Changed = true;
129     }
130 
131     Defs.clear();
132   }
133 
134   return Changed;
135 }
136