1*6ddf2a82SIvan Kosarev //===- AMDGPUSetWavePriority.cpp - Set wave priority ----------------------===//
2*6ddf2a82SIvan Kosarev //
3*6ddf2a82SIvan Kosarev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*6ddf2a82SIvan Kosarev // See https://llvm.org/LICENSE.txt for license information.
5*6ddf2a82SIvan Kosarev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*6ddf2a82SIvan Kosarev //
7*6ddf2a82SIvan Kosarev //===----------------------------------------------------------------------===//
8*6ddf2a82SIvan Kosarev //
9*6ddf2a82SIvan Kosarev /// \file
10*6ddf2a82SIvan Kosarev /// Pass to temporarily raise the wave priority beginning the start of
11*6ddf2a82SIvan Kosarev /// the shader function until its last VMEM instructions to allow younger
12*6ddf2a82SIvan Kosarev /// waves to issue their VMEM instructions as well.
13*6ddf2a82SIvan Kosarev //
14*6ddf2a82SIvan Kosarev //===----------------------------------------------------------------------===//
15*6ddf2a82SIvan Kosarev 
16*6ddf2a82SIvan Kosarev #include "AMDGPU.h"
17*6ddf2a82SIvan Kosarev #include "GCNSubtarget.h"
18*6ddf2a82SIvan Kosarev #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
19*6ddf2a82SIvan Kosarev #include "SIInstrInfo.h"
20*6ddf2a82SIvan Kosarev #include "llvm/ADT/PostOrderIterator.h"
21*6ddf2a82SIvan Kosarev #include "llvm/CodeGen/MachineFunctionPass.h"
22*6ddf2a82SIvan Kosarev #include "llvm/InitializePasses.h"
23*6ddf2a82SIvan Kosarev #include "llvm/Support/Allocator.h"
24*6ddf2a82SIvan Kosarev 
25*6ddf2a82SIvan Kosarev using namespace llvm;
26*6ddf2a82SIvan Kosarev 
27*6ddf2a82SIvan Kosarev #define DEBUG_TYPE "amdgpu-set-wave-priority"
28*6ddf2a82SIvan Kosarev 
29*6ddf2a82SIvan Kosarev namespace {
30*6ddf2a82SIvan Kosarev 
31*6ddf2a82SIvan Kosarev struct MBBInfo {
32*6ddf2a82SIvan Kosarev   MBBInfo() = default;
33*6ddf2a82SIvan Kosarev   bool MayReachVMEMLoad = false;
34*6ddf2a82SIvan Kosarev };
35*6ddf2a82SIvan Kosarev 
36*6ddf2a82SIvan Kosarev using MBBInfoSet = DenseMap<const MachineBasicBlock *, MBBInfo>;
37*6ddf2a82SIvan Kosarev 
38*6ddf2a82SIvan Kosarev class AMDGPUSetWavePriority : public MachineFunctionPass {
39*6ddf2a82SIvan Kosarev public:
40*6ddf2a82SIvan Kosarev   static char ID;
41*6ddf2a82SIvan Kosarev 
AMDGPUSetWavePriority()42*6ddf2a82SIvan Kosarev   AMDGPUSetWavePriority() : MachineFunctionPass(ID) {}
43*6ddf2a82SIvan Kosarev 
getPassName() const44*6ddf2a82SIvan Kosarev   StringRef getPassName() const override { return "Set wave priority"; }
45*6ddf2a82SIvan Kosarev 
46*6ddf2a82SIvan Kosarev   bool runOnMachineFunction(MachineFunction &MF) override;
47*6ddf2a82SIvan Kosarev 
48*6ddf2a82SIvan Kosarev private:
49*6ddf2a82SIvan Kosarev   MachineInstr *BuildSetprioMI(MachineFunction &MF, unsigned priority) const;
50*6ddf2a82SIvan Kosarev 
51*6ddf2a82SIvan Kosarev   const SIInstrInfo *TII;
52*6ddf2a82SIvan Kosarev };
53*6ddf2a82SIvan Kosarev 
54*6ddf2a82SIvan Kosarev } // End anonymous namespace.
55*6ddf2a82SIvan Kosarev 
56*6ddf2a82SIvan Kosarev INITIALIZE_PASS(AMDGPUSetWavePriority, DEBUG_TYPE, "Set wave priority", false,
57*6ddf2a82SIvan Kosarev                 false)
58*6ddf2a82SIvan Kosarev 
59*6ddf2a82SIvan Kosarev char AMDGPUSetWavePriority::ID = 0;
60*6ddf2a82SIvan Kosarev 
createAMDGPUSetWavePriorityPass()61*6ddf2a82SIvan Kosarev FunctionPass *llvm::createAMDGPUSetWavePriorityPass() {
62*6ddf2a82SIvan Kosarev   return new AMDGPUSetWavePriority();
63*6ddf2a82SIvan Kosarev }
64*6ddf2a82SIvan Kosarev 
BuildSetprioMI(MachineFunction & MF,unsigned priority) const65*6ddf2a82SIvan Kosarev MachineInstr *AMDGPUSetWavePriority::BuildSetprioMI(MachineFunction &MF,
66*6ddf2a82SIvan Kosarev                                                     unsigned priority) const {
67*6ddf2a82SIvan Kosarev   return BuildMI(MF, DebugLoc(), TII->get(AMDGPU::S_SETPRIO)).addImm(priority);
68*6ddf2a82SIvan Kosarev }
69*6ddf2a82SIvan Kosarev 
70*6ddf2a82SIvan Kosarev // Checks that for every predecessor Pred that can reach a VMEM load,
71*6ddf2a82SIvan Kosarev // none of Pred's successors can reach a VMEM load.
CanLowerPriorityDirectlyInPredecessors(const MachineBasicBlock & MBB,MBBInfoSet & MBBInfos)72*6ddf2a82SIvan Kosarev static bool CanLowerPriorityDirectlyInPredecessors(const MachineBasicBlock &MBB,
73*6ddf2a82SIvan Kosarev                                                    MBBInfoSet &MBBInfos) {
74*6ddf2a82SIvan Kosarev   for (const MachineBasicBlock *Pred : MBB.predecessors()) {
75*6ddf2a82SIvan Kosarev     if (!MBBInfos[Pred].MayReachVMEMLoad)
76*6ddf2a82SIvan Kosarev       continue;
77*6ddf2a82SIvan Kosarev     for (const MachineBasicBlock *Succ : Pred->successors()) {
78*6ddf2a82SIvan Kosarev       if (MBBInfos[Succ].MayReachVMEMLoad)
79*6ddf2a82SIvan Kosarev         return false;
80*6ddf2a82SIvan Kosarev     }
81*6ddf2a82SIvan Kosarev   }
82*6ddf2a82SIvan Kosarev   return true;
83*6ddf2a82SIvan Kosarev }
84*6ddf2a82SIvan Kosarev 
isVMEMLoad(const MachineInstr & MI)85*6ddf2a82SIvan Kosarev static bool isVMEMLoad(const MachineInstr &MI) {
86*6ddf2a82SIvan Kosarev   return SIInstrInfo::isVMEM(MI) && MI.mayLoad();
87*6ddf2a82SIvan Kosarev }
88*6ddf2a82SIvan Kosarev 
runOnMachineFunction(MachineFunction & MF)89*6ddf2a82SIvan Kosarev bool AMDGPUSetWavePriority::runOnMachineFunction(MachineFunction &MF) {
90*6ddf2a82SIvan Kosarev   const unsigned HighPriority = 3;
91*6ddf2a82SIvan Kosarev   const unsigned LowPriority = 0;
92*6ddf2a82SIvan Kosarev 
93*6ddf2a82SIvan Kosarev   Function &F = MF.getFunction();
94*6ddf2a82SIvan Kosarev   if (skipFunction(F) || !AMDGPU::isEntryFunctionCC(F.getCallingConv()))
95*6ddf2a82SIvan Kosarev     return false;
96*6ddf2a82SIvan Kosarev 
97*6ddf2a82SIvan Kosarev   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
98*6ddf2a82SIvan Kosarev   TII = ST.getInstrInfo();
99*6ddf2a82SIvan Kosarev 
100*6ddf2a82SIvan Kosarev   MBBInfoSet MBBInfos;
101*6ddf2a82SIvan Kosarev   SmallVector<const MachineBasicBlock *, 16> Worklist;
102*6ddf2a82SIvan Kosarev   for (MachineBasicBlock &MBB : MF) {
103*6ddf2a82SIvan Kosarev     if (any_of(MBB, isVMEMLoad))
104*6ddf2a82SIvan Kosarev       Worklist.push_back(&MBB);
105*6ddf2a82SIvan Kosarev   }
106*6ddf2a82SIvan Kosarev 
107*6ddf2a82SIvan Kosarev   // Mark blocks from which control may reach VMEM loads.
108*6ddf2a82SIvan Kosarev   while (!Worklist.empty()) {
109*6ddf2a82SIvan Kosarev     const MachineBasicBlock *MBB = Worklist.pop_back_val();
110*6ddf2a82SIvan Kosarev     MBBInfo &Info = MBBInfos[MBB];
111*6ddf2a82SIvan Kosarev     if (!Info.MayReachVMEMLoad) {
112*6ddf2a82SIvan Kosarev       Info.MayReachVMEMLoad = true;
113*6ddf2a82SIvan Kosarev       Worklist.append(MBB->pred_begin(), MBB->pred_end());
114*6ddf2a82SIvan Kosarev     }
115*6ddf2a82SIvan Kosarev   }
116*6ddf2a82SIvan Kosarev 
117*6ddf2a82SIvan Kosarev   MachineBasicBlock &Entry = MF.front();
118*6ddf2a82SIvan Kosarev   if (!MBBInfos[&Entry].MayReachVMEMLoad)
119*6ddf2a82SIvan Kosarev     return false;
120*6ddf2a82SIvan Kosarev 
121*6ddf2a82SIvan Kosarev   // Raise the priority at the beginning of the shader.
122*6ddf2a82SIvan Kosarev   MachineBasicBlock::iterator I = Entry.begin(), E = Entry.end();
123*6ddf2a82SIvan Kosarev   while (I != E && !SIInstrInfo::isVALU(*I) && !I->isTerminator())
124*6ddf2a82SIvan Kosarev     ++I;
125*6ddf2a82SIvan Kosarev   Entry.insert(I, BuildSetprioMI(MF, HighPriority));
126*6ddf2a82SIvan Kosarev 
127*6ddf2a82SIvan Kosarev   // Lower the priority on edges where control leaves blocks from which
128*6ddf2a82SIvan Kosarev   // VMEM loads are reachable.
129*6ddf2a82SIvan Kosarev   SmallSet<MachineBasicBlock *, 16> PriorityLoweringBlocks;
130*6ddf2a82SIvan Kosarev   for (MachineBasicBlock &MBB : MF) {
131*6ddf2a82SIvan Kosarev     if (MBBInfos[&MBB].MayReachVMEMLoad) {
132*6ddf2a82SIvan Kosarev       if (MBB.succ_empty())
133*6ddf2a82SIvan Kosarev         PriorityLoweringBlocks.insert(&MBB);
134*6ddf2a82SIvan Kosarev       continue;
135*6ddf2a82SIvan Kosarev     }
136*6ddf2a82SIvan Kosarev 
137*6ddf2a82SIvan Kosarev     if (CanLowerPriorityDirectlyInPredecessors(MBB, MBBInfos)) {
138*6ddf2a82SIvan Kosarev       for (MachineBasicBlock *Pred : MBB.predecessors()) {
139*6ddf2a82SIvan Kosarev         if (MBBInfos[Pred].MayReachVMEMLoad)
140*6ddf2a82SIvan Kosarev           PriorityLoweringBlocks.insert(Pred);
141*6ddf2a82SIvan Kosarev       }
142*6ddf2a82SIvan Kosarev       continue;
143*6ddf2a82SIvan Kosarev     }
144*6ddf2a82SIvan Kosarev 
145*6ddf2a82SIvan Kosarev     // Where lowering the priority in predecessors is not possible, the
146*6ddf2a82SIvan Kosarev     // block receiving control either was not part of a loop in the first
147*6ddf2a82SIvan Kosarev     // place or the loop simplification/canonicalization pass should have
148*6ddf2a82SIvan Kosarev     // already tried to split the edge and insert a preheader, and if for
149*6ddf2a82SIvan Kosarev     // whatever reason it failed to do so, then this leaves us with the
150*6ddf2a82SIvan Kosarev     // only option of lowering the priority within the loop.
151*6ddf2a82SIvan Kosarev     PriorityLoweringBlocks.insert(&MBB);
152*6ddf2a82SIvan Kosarev   }
153*6ddf2a82SIvan Kosarev 
154*6ddf2a82SIvan Kosarev   for (MachineBasicBlock *MBB : PriorityLoweringBlocks) {
155*6ddf2a82SIvan Kosarev     MachineBasicBlock::iterator I = MBB->end(), B = MBB->begin();
156*6ddf2a82SIvan Kosarev     while (I != B) {
157*6ddf2a82SIvan Kosarev       if (isVMEMLoad(*--I)) {
158*6ddf2a82SIvan Kosarev         ++I;
159*6ddf2a82SIvan Kosarev         break;
160*6ddf2a82SIvan Kosarev       }
161*6ddf2a82SIvan Kosarev     }
162*6ddf2a82SIvan Kosarev     MBB->insert(I, BuildSetprioMI(MF, LowPriority));
163*6ddf2a82SIvan Kosarev   }
164*6ddf2a82SIvan Kosarev 
165*6ddf2a82SIvan Kosarev   return true;
166*6ddf2a82SIvan Kosarev }
167