1 //===- SIPreAllocateWWMRegs.cpp - WWM Register Pre-allocation -------------===//
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 /// Pass to pre-allocated WWM registers
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "AMDGPU.h"
15 #include "GCNSubtarget.h"
16 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
17 #include "SIMachineFunctionInfo.h"
18 #include "llvm/ADT/PostOrderIterator.h"
19 #include "llvm/CodeGen/LiveIntervals.h"
20 #include "llvm/CodeGen/LiveRegMatrix.h"
21 #include "llvm/CodeGen/MachineFrameInfo.h"
22 #include "llvm/CodeGen/MachineFunctionPass.h"
23 #include "llvm/CodeGen/RegisterClassInfo.h"
24 #include "llvm/CodeGen/VirtRegMap.h"
25 #include "llvm/InitializePasses.h"
26 
27 using namespace llvm;
28 
29 #define DEBUG_TYPE "si-pre-allocate-wwm-regs"
30 
31 namespace {
32 
33 class SIPreAllocateWWMRegs : public MachineFunctionPass {
34 private:
35   const SIInstrInfo *TII;
36   const SIRegisterInfo *TRI;
37   MachineRegisterInfo *MRI;
38   LiveIntervals *LIS;
39   LiveRegMatrix *Matrix;
40   VirtRegMap *VRM;
41   RegisterClassInfo RegClassInfo;
42 
43   std::vector<unsigned> RegsToRewrite;
44 #ifndef NDEBUG
45   void printWWMInfo(const MachineInstr &MI);
46 #endif
47 
48 public:
49   static char ID;
50 
51   SIPreAllocateWWMRegs() : MachineFunctionPass(ID) {
52     initializeSIPreAllocateWWMRegsPass(*PassRegistry::getPassRegistry());
53   }
54 
55   bool runOnMachineFunction(MachineFunction &MF) override;
56 
57   void getAnalysisUsage(AnalysisUsage &AU) const override {
58     AU.addRequired<LiveIntervals>();
59     AU.addPreserved<LiveIntervals>();
60     AU.addRequired<VirtRegMap>();
61     AU.addRequired<LiveRegMatrix>();
62     AU.addPreserved<SlotIndexes>();
63     AU.setPreservesCFG();
64     MachineFunctionPass::getAnalysisUsage(AU);
65   }
66 
67 private:
68   bool processDef(MachineOperand &MO);
69   void rewriteRegs(MachineFunction &MF);
70 };
71 
72 } // End anonymous namespace.
73 
74 INITIALIZE_PASS_BEGIN(SIPreAllocateWWMRegs, DEBUG_TYPE,
75                 "SI Pre-allocate WWM Registers", false, false)
76 INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
77 INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
78 INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix)
79 INITIALIZE_PASS_END(SIPreAllocateWWMRegs, DEBUG_TYPE,
80                 "SI Pre-allocate WWM Registers", false, false)
81 
82 char SIPreAllocateWWMRegs::ID = 0;
83 
84 char &llvm::SIPreAllocateWWMRegsID = SIPreAllocateWWMRegs::ID;
85 
86 FunctionPass *llvm::createSIPreAllocateWWMRegsPass() {
87   return new SIPreAllocateWWMRegs();
88 }
89 
90 bool SIPreAllocateWWMRegs::processDef(MachineOperand &MO) {
91   Register Reg = MO.getReg();
92   if (Reg.isPhysical())
93     return false;
94 
95   if (!TRI->isVGPR(*MRI, Reg))
96     return false;
97 
98   if (VRM->hasPhys(Reg))
99     return false;
100 
101   LiveInterval &LI = LIS->getInterval(Reg);
102 
103   for (MCRegister PhysReg : RegClassInfo.getOrder(MRI->getRegClass(Reg))) {
104     if (!MRI->isPhysRegUsed(PhysReg) &&
105         Matrix->checkInterference(LI, PhysReg) == LiveRegMatrix::IK_Free) {
106       Matrix->assign(LI, PhysReg);
107       assert(PhysReg != 0);
108       RegsToRewrite.push_back(Reg);
109       return true;
110     }
111   }
112 
113   llvm_unreachable("physreg not found for WWM expression");
114 }
115 
116 void SIPreAllocateWWMRegs::rewriteRegs(MachineFunction &MF) {
117   for (MachineBasicBlock &MBB : MF) {
118     for (MachineInstr &MI : MBB) {
119       for (MachineOperand &MO : MI.operands()) {
120         if (!MO.isReg())
121           continue;
122 
123         const Register VirtReg = MO.getReg();
124         if (VirtReg.isPhysical())
125           continue;
126 
127         if (!VRM->hasPhys(VirtReg))
128           continue;
129 
130         Register PhysReg = VRM->getPhys(VirtReg);
131         const unsigned SubReg = MO.getSubReg();
132         if (SubReg != 0) {
133           PhysReg = TRI->getSubReg(PhysReg, SubReg);
134           MO.setSubReg(0);
135         }
136 
137         MO.setReg(PhysReg);
138         MO.setIsRenamable(false);
139       }
140     }
141   }
142 
143   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
144   MachineFrameInfo &FrameInfo = MF.getFrameInfo();
145 
146   for (unsigned Reg : RegsToRewrite) {
147     LIS->removeInterval(Reg);
148 
149     const Register PhysReg = VRM->getPhys(Reg);
150     assert(PhysReg != 0);
151 
152     // Check if PhysReg is already reserved
153     if (!MFI->WWMReservedRegs.count(PhysReg)) {
154       Optional<int> FI;
155       if (!MFI->isEntryFunction()) {
156         // Create a stack object for a possible spill in the function prologue.
157         // Note: Non-CSR VGPR also need this as we may overwrite inactive lanes.
158         const TargetRegisterClass *RC = TRI->getPhysRegClass(PhysReg);
159         FI = FrameInfo.CreateSpillStackObject(TRI->getSpillSize(*RC),
160                                               TRI->getSpillAlign(*RC));
161       }
162       MFI->reserveWWMRegister(PhysReg, FI);
163     }
164   }
165 
166   RegsToRewrite.clear();
167 
168   // Update the set of reserved registers to include WWM ones.
169   MRI->freezeReservedRegs(MF);
170 }
171 
172 #ifndef NDEBUG
173 LLVM_DUMP_METHOD void
174 SIPreAllocateWWMRegs::printWWMInfo(const MachineInstr &MI) {
175 
176   unsigned Opc = MI.getOpcode();
177 
178   if (Opc == AMDGPU::ENTER_STRICT_WWM || Opc == AMDGPU::ENTER_STRICT_WQM) {
179     dbgs() << "Entering ";
180   } else {
181     assert(Opc == AMDGPU::EXIT_STRICT_WWM || Opc == AMDGPU::EXIT_STRICT_WQM);
182     dbgs() << "Exiting ";
183   }
184 
185   if (Opc == AMDGPU::ENTER_STRICT_WWM || Opc == AMDGPU::EXIT_STRICT_WWM) {
186     dbgs() << "Strict WWM ";
187   } else {
188     assert(Opc == AMDGPU::ENTER_STRICT_WQM || Opc == AMDGPU::EXIT_STRICT_WQM);
189     dbgs() << "Strict WQM ";
190   }
191 
192   dbgs() << "region: " << MI;
193 }
194 
195 #endif
196 
197 bool SIPreAllocateWWMRegs::runOnMachineFunction(MachineFunction &MF) {
198   LLVM_DEBUG(dbgs() << "SIPreAllocateWWMRegs: function " << MF.getName() << "\n");
199 
200   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
201 
202   TII = ST.getInstrInfo();
203   TRI = &TII->getRegisterInfo();
204   MRI = &MF.getRegInfo();
205 
206   LIS = &getAnalysis<LiveIntervals>();
207   Matrix = &getAnalysis<LiveRegMatrix>();
208   VRM = &getAnalysis<VirtRegMap>();
209 
210   RegClassInfo.runOnMachineFunction(MF);
211 
212   bool RegsAssigned = false;
213 
214   // We use a reverse post-order traversal of the control-flow graph to
215   // guarantee that we visit definitions in dominance order. Since WWM
216   // expressions are guaranteed to never involve phi nodes, and we can only
217   // escape WWM through the special WWM instruction, this means that this is a
218   // perfect elimination order, so we can never do any better.
219   ReversePostOrderTraversal<MachineFunction*> RPOT(&MF);
220 
221   for (MachineBasicBlock *MBB : RPOT) {
222     bool InWWM = false;
223     for (MachineInstr &MI : *MBB) {
224       if (MI.getOpcode() == AMDGPU::V_SET_INACTIVE_B32 ||
225           MI.getOpcode() == AMDGPU::V_SET_INACTIVE_B64)
226         RegsAssigned |= processDef(MI.getOperand(0));
227 
228       if (MI.getOpcode() == AMDGPU::ENTER_STRICT_WWM ||
229           MI.getOpcode() == AMDGPU::ENTER_STRICT_WQM) {
230         LLVM_DEBUG(printWWMInfo(MI));
231         InWWM = true;
232         continue;
233       }
234 
235       if (MI.getOpcode() == AMDGPU::EXIT_STRICT_WWM ||
236           MI.getOpcode() == AMDGPU::EXIT_STRICT_WQM) {
237         LLVM_DEBUG(printWWMInfo(MI));
238         InWWM = false;
239       }
240 
241       if (!InWWM)
242         continue;
243 
244       LLVM_DEBUG(dbgs() << "Processing " << MI);
245 
246       for (MachineOperand &DefOpnd : MI.defs()) {
247         RegsAssigned |= processDef(DefOpnd);
248       }
249     }
250   }
251 
252   if (!RegsAssigned)
253     return false;
254 
255   rewriteRegs(MF);
256   return true;
257 }
258