1fe5f4c39SCarl Ritson //===-- SILateBranchLowering.cpp - Final preparation of branches ----------===//
2fe5f4c39SCarl Ritson //
3fe5f4c39SCarl Ritson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe5f4c39SCarl Ritson // See https://llvm.org/LICENSE.txt for license information.
5fe5f4c39SCarl Ritson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe5f4c39SCarl Ritson //
7fe5f4c39SCarl Ritson //===----------------------------------------------------------------------===//
8fe5f4c39SCarl Ritson //
9fe5f4c39SCarl Ritson /// \file
10fe5f4c39SCarl Ritson /// This pass mainly lowers early terminate pseudo instructions.
11fe5f4c39SCarl Ritson //
12fe5f4c39SCarl Ritson //===----------------------------------------------------------------------===//
13fe5f4c39SCarl Ritson 
14fe5f4c39SCarl Ritson #include "AMDGPU.h"
15fe5f4c39SCarl Ritson #include "GCNSubtarget.h"
16fe5f4c39SCarl Ritson #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
17fe5f4c39SCarl Ritson #include "SIMachineFunctionInfo.h"
18fe5f4c39SCarl Ritson #include "llvm/CodeGen/MachineDominators.h"
19fe5f4c39SCarl Ritson #include "llvm/InitializePasses.h"
20fe5f4c39SCarl Ritson 
21fe5f4c39SCarl Ritson using namespace llvm;
22fe5f4c39SCarl Ritson 
23fe5f4c39SCarl Ritson #define DEBUG_TYPE "si-late-branch-lowering"
24fe5f4c39SCarl Ritson 
25fe5f4c39SCarl Ritson namespace {
26fe5f4c39SCarl Ritson 
27fe5f4c39SCarl Ritson class SILateBranchLowering : public MachineFunctionPass {
28fe5f4c39SCarl Ritson private:
29fe5f4c39SCarl Ritson   const SIRegisterInfo *TRI = nullptr;
30fe5f4c39SCarl Ritson   const SIInstrInfo *TII = nullptr;
31fe5f4c39SCarl Ritson   MachineDominatorTree *MDT = nullptr;
32fe5f4c39SCarl Ritson 
33fe5f4c39SCarl Ritson   void earlyTerm(MachineInstr &MI, MachineBasicBlock *EarlyExitBlock);
34fe5f4c39SCarl Ritson 
35fe5f4c39SCarl Ritson public:
36fe5f4c39SCarl Ritson   static char ID;
37fe5f4c39SCarl Ritson 
38fe5f4c39SCarl Ritson   unsigned MovOpc;
39fe5f4c39SCarl Ritson   Register ExecReg;
40fe5f4c39SCarl Ritson 
SILateBranchLowering()41fe5f4c39SCarl Ritson   SILateBranchLowering() : MachineFunctionPass(ID) {}
42fe5f4c39SCarl Ritson 
43fe5f4c39SCarl Ritson   bool runOnMachineFunction(MachineFunction &MF) override;
44fe5f4c39SCarl Ritson 
getPassName() const45fe5f4c39SCarl Ritson   StringRef getPassName() const override {
46fe5f4c39SCarl Ritson     return "SI Final Branch Preparation";
47fe5f4c39SCarl Ritson   }
48fe5f4c39SCarl Ritson 
getAnalysisUsage(AnalysisUsage & AU) const49fe5f4c39SCarl Ritson   void getAnalysisUsage(AnalysisUsage &AU) const override {
50fe5f4c39SCarl Ritson     AU.addRequired<MachineDominatorTree>();
51fe5f4c39SCarl Ritson     AU.addPreserved<MachineDominatorTree>();
52fe5f4c39SCarl Ritson     MachineFunctionPass::getAnalysisUsage(AU);
53fe5f4c39SCarl Ritson   }
54fe5f4c39SCarl Ritson };
55fe5f4c39SCarl Ritson 
56fe5f4c39SCarl Ritson } // end anonymous namespace
57fe5f4c39SCarl Ritson 
58fe5f4c39SCarl Ritson char SILateBranchLowering::ID = 0;
59fe5f4c39SCarl Ritson 
60fe5f4c39SCarl Ritson INITIALIZE_PASS_BEGIN(SILateBranchLowering, DEBUG_TYPE,
61fe5f4c39SCarl Ritson                       "SI insert s_cbranch_execz instructions", false, false)
62fe5f4c39SCarl Ritson INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
63fe5f4c39SCarl Ritson INITIALIZE_PASS_END(SILateBranchLowering, DEBUG_TYPE,
64fe5f4c39SCarl Ritson                     "SI insert s_cbranch_execz instructions", false, false)
65fe5f4c39SCarl Ritson 
66fe5f4c39SCarl Ritson char &llvm::SILateBranchLoweringPassID = SILateBranchLowering::ID;
67fe5f4c39SCarl Ritson 
generateEndPgm(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,DebugLoc DL,const SIInstrInfo * TII,MachineFunction & MF)68fe5f4c39SCarl Ritson static void generateEndPgm(MachineBasicBlock &MBB,
69fe5f4c39SCarl Ritson                            MachineBasicBlock::iterator I, DebugLoc DL,
709dcd75f8SCarl Ritson                            const SIInstrInfo *TII, MachineFunction &MF) {
719dcd75f8SCarl Ritson   const Function &F = MF.getFunction();
729dcd75f8SCarl Ritson   bool IsPS = F.getCallingConv() == CallingConv::AMDGPU_PS;
739dcd75f8SCarl Ritson 
749dcd75f8SCarl Ritson   // Check if hardware has been configured to expect color or depth exports.
75*62abc8c2SCarl Ritson   bool HasColorExports = AMDGPU::getHasColorExport(F);
76*62abc8c2SCarl Ritson   bool HasDepthExports = AMDGPU::getHasDepthExport(F);
77*62abc8c2SCarl Ritson   bool HasExports = HasColorExports || HasDepthExports;
789dcd75f8SCarl Ritson 
799dcd75f8SCarl Ritson   // Prior to GFX10, hardware always expects at least one export for PS.
809dcd75f8SCarl Ritson   bool MustExport = !AMDGPU::isGFX10Plus(TII->getSubtarget());
819dcd75f8SCarl Ritson 
829dcd75f8SCarl Ritson   if (IsPS && (HasExports || MustExport)) {
839dcd75f8SCarl Ritson     // Generate "null export" if hardware is expecting PS to export.
84*62abc8c2SCarl Ritson     const GCNSubtarget &ST = MBB.getParent()->getSubtarget<GCNSubtarget>();
85*62abc8c2SCarl Ritson     int Target =
86*62abc8c2SCarl Ritson         ST.hasNullExportTarget()
87*62abc8c2SCarl Ritson             ? AMDGPU::Exp::ET_NULL
88*62abc8c2SCarl Ritson             : (HasColorExports ? AMDGPU::Exp::ET_MRT0 : AMDGPU::Exp::ET_MRTZ);
89fe5f4c39SCarl Ritson     BuildMI(MBB, I, DL, TII->get(AMDGPU::EXP_DONE))
90*62abc8c2SCarl Ritson         .addImm(Target)
91fe5f4c39SCarl Ritson         .addReg(AMDGPU::VGPR0, RegState::Undef)
92fe5f4c39SCarl Ritson         .addReg(AMDGPU::VGPR0, RegState::Undef)
93fe5f4c39SCarl Ritson         .addReg(AMDGPU::VGPR0, RegState::Undef)
94fe5f4c39SCarl Ritson         .addReg(AMDGPU::VGPR0, RegState::Undef)
95fe5f4c39SCarl Ritson         .addImm(1)  // vm
96fe5f4c39SCarl Ritson         .addImm(0)  // compr
97fe5f4c39SCarl Ritson         .addImm(0); // en
98fe5f4c39SCarl Ritson   }
999dcd75f8SCarl Ritson 
100fe5f4c39SCarl Ritson   // s_endpgm
101fe5f4c39SCarl Ritson   BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ENDPGM)).addImm(0);
102fe5f4c39SCarl Ritson }
103fe5f4c39SCarl Ritson 
splitBlock(MachineBasicBlock & MBB,MachineInstr & MI,MachineDominatorTree * MDT)104fe5f4c39SCarl Ritson static void splitBlock(MachineBasicBlock &MBB, MachineInstr &MI,
105fe5f4c39SCarl Ritson                        MachineDominatorTree *MDT) {
106fe5f4c39SCarl Ritson   MachineBasicBlock *SplitBB = MBB.splitAt(MI, /*UpdateLiveIns*/ true);
107fe5f4c39SCarl Ritson 
108fe5f4c39SCarl Ritson   // Update dominator tree
109fe5f4c39SCarl Ritson   using DomTreeT = DomTreeBase<MachineBasicBlock>;
110fe5f4c39SCarl Ritson   SmallVector<DomTreeT::UpdateType, 16> DTUpdates;
111fe5f4c39SCarl Ritson   for (MachineBasicBlock *Succ : SplitBB->successors()) {
112fe5f4c39SCarl Ritson     DTUpdates.push_back({DomTreeT::Insert, SplitBB, Succ});
113fe5f4c39SCarl Ritson     DTUpdates.push_back({DomTreeT::Delete, &MBB, Succ});
114fe5f4c39SCarl Ritson   }
115fe5f4c39SCarl Ritson   DTUpdates.push_back({DomTreeT::Insert, &MBB, SplitBB});
116fe5f4c39SCarl Ritson   MDT->getBase().applyUpdates(DTUpdates);
117fe5f4c39SCarl Ritson }
118fe5f4c39SCarl Ritson 
earlyTerm(MachineInstr & MI,MachineBasicBlock * EarlyExitBlock)119fe5f4c39SCarl Ritson void SILateBranchLowering::earlyTerm(MachineInstr &MI,
120fe5f4c39SCarl Ritson                                      MachineBasicBlock *EarlyExitBlock) {
121fe5f4c39SCarl Ritson   MachineBasicBlock &MBB = *MI.getParent();
122fe5f4c39SCarl Ritson   const DebugLoc DL = MI.getDebugLoc();
123fe5f4c39SCarl Ritson 
124fe5f4c39SCarl Ritson   auto BranchMI = BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_CBRANCH_SCC0))
125fe5f4c39SCarl Ritson                       .addMBB(EarlyExitBlock);
126fe5f4c39SCarl Ritson   auto Next = std::next(MI.getIterator());
127fe5f4c39SCarl Ritson 
128fe5f4c39SCarl Ritson   if (Next != MBB.end() && !Next->isTerminator())
129fe5f4c39SCarl Ritson     splitBlock(MBB, *BranchMI, MDT);
130fe5f4c39SCarl Ritson 
131fe5f4c39SCarl Ritson   MBB.addSuccessor(EarlyExitBlock);
132fe5f4c39SCarl Ritson   MDT->getBase().insertEdge(&MBB, EarlyExitBlock);
133fe5f4c39SCarl Ritson }
134fe5f4c39SCarl Ritson 
runOnMachineFunction(MachineFunction & MF)135fe5f4c39SCarl Ritson bool SILateBranchLowering::runOnMachineFunction(MachineFunction &MF) {
136fe5f4c39SCarl Ritson   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
137fe5f4c39SCarl Ritson   TII = ST.getInstrInfo();
138fe5f4c39SCarl Ritson   TRI = &TII->getRegisterInfo();
139fe5f4c39SCarl Ritson   MDT = &getAnalysis<MachineDominatorTree>();
140fe5f4c39SCarl Ritson 
141fe5f4c39SCarl Ritson   MovOpc = ST.isWave32() ? AMDGPU::S_MOV_B32 : AMDGPU::S_MOV_B64;
142fe5f4c39SCarl Ritson   ExecReg = ST.isWave32() ? AMDGPU::EXEC_LO : AMDGPU::EXEC;
143fe5f4c39SCarl Ritson 
144fe5f4c39SCarl Ritson   SmallVector<MachineInstr *, 4> EarlyTermInstrs;
145fe5f4c39SCarl Ritson   SmallVector<MachineInstr *, 1> EpilogInstrs;
146fe5f4c39SCarl Ritson   bool MadeChange = false;
147fe5f4c39SCarl Ritson 
148fe5f4c39SCarl Ritson   for (MachineBasicBlock &MBB : MF) {
1494bef0304SKazu Hirata     for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
150fe5f4c39SCarl Ritson       switch (MI.getOpcode()) {
151fe5f4c39SCarl Ritson       case AMDGPU::S_BRANCH:
152fe5f4c39SCarl Ritson         // Optimize out branches to the next block.
153fe5f4c39SCarl Ritson         // This only occurs in -O0 when BranchFolding is not executed.
154fe5f4c39SCarl Ritson         if (MBB.isLayoutSuccessor(MI.getOperand(0).getMBB())) {
155fe5f4c39SCarl Ritson           assert(&MI == &MBB.back());
156fe5f4c39SCarl Ritson           MI.eraseFromParent();
157fe5f4c39SCarl Ritson           MadeChange = true;
158fe5f4c39SCarl Ritson         }
159fe5f4c39SCarl Ritson         break;
160fe5f4c39SCarl Ritson 
161fe5f4c39SCarl Ritson       case AMDGPU::SI_EARLY_TERMINATE_SCC0:
162fe5f4c39SCarl Ritson         EarlyTermInstrs.push_back(&MI);
163fe5f4c39SCarl Ritson         break;
164fe5f4c39SCarl Ritson 
165fe5f4c39SCarl Ritson       case AMDGPU::SI_RETURN_TO_EPILOG:
166fe5f4c39SCarl Ritson         EpilogInstrs.push_back(&MI);
167fe5f4c39SCarl Ritson         break;
168fe5f4c39SCarl Ritson 
169fe5f4c39SCarl Ritson       default:
170fe5f4c39SCarl Ritson         break;
171fe5f4c39SCarl Ritson       }
172fe5f4c39SCarl Ritson     }
173fe5f4c39SCarl Ritson   }
174fe5f4c39SCarl Ritson 
175fe5f4c39SCarl Ritson   // Lower any early exit branches first
176fe5f4c39SCarl Ritson   if (!EarlyTermInstrs.empty()) {
177fe5f4c39SCarl Ritson     MachineBasicBlock *EarlyExitBlock = MF.CreateMachineBasicBlock();
178fe5f4c39SCarl Ritson     DebugLoc DL;
179fe5f4c39SCarl Ritson 
180fe5f4c39SCarl Ritson     MF.insert(MF.end(), EarlyExitBlock);
181fe5f4c39SCarl Ritson     BuildMI(*EarlyExitBlock, EarlyExitBlock->end(), DL, TII->get(MovOpc),
182fe5f4c39SCarl Ritson             ExecReg)
183fe5f4c39SCarl Ritson         .addImm(0);
1849dcd75f8SCarl Ritson     generateEndPgm(*EarlyExitBlock, EarlyExitBlock->end(), DL, TII, MF);
185fe5f4c39SCarl Ritson 
186fe5f4c39SCarl Ritson     for (MachineInstr *Instr : EarlyTermInstrs) {
187fe5f4c39SCarl Ritson       // Early termination in GS does nothing
188fe5f4c39SCarl Ritson       if (MF.getFunction().getCallingConv() != CallingConv::AMDGPU_GS)
189fe5f4c39SCarl Ritson         earlyTerm(*Instr, EarlyExitBlock);
190fe5f4c39SCarl Ritson       Instr->eraseFromParent();
191fe5f4c39SCarl Ritson     }
192fe5f4c39SCarl Ritson 
193fe5f4c39SCarl Ritson     EarlyTermInstrs.clear();
194fe5f4c39SCarl Ritson     MadeChange = true;
195fe5f4c39SCarl Ritson   }
196fe5f4c39SCarl Ritson 
197fe5f4c39SCarl Ritson   // Now check return to epilog instructions occur at function end
198fe5f4c39SCarl Ritson   if (!EpilogInstrs.empty()) {
199fe5f4c39SCarl Ritson     MachineBasicBlock *EmptyMBBAtEnd = nullptr;
200fe5f4c39SCarl Ritson     assert(!MF.getInfo<SIMachineFunctionInfo>()->returnsVoid());
201fe5f4c39SCarl Ritson 
202fe5f4c39SCarl Ritson     // If there are multiple returns to epilog then all will
203fe5f4c39SCarl Ritson     // become jumps to new empty end block.
204fe5f4c39SCarl Ritson     if (EpilogInstrs.size() > 1) {
205fe5f4c39SCarl Ritson       EmptyMBBAtEnd = MF.CreateMachineBasicBlock();
206fe5f4c39SCarl Ritson       MF.insert(MF.end(), EmptyMBBAtEnd);
207fe5f4c39SCarl Ritson     }
208fe5f4c39SCarl Ritson 
209fe5f4c39SCarl Ritson     for (auto MI : EpilogInstrs) {
210fe5f4c39SCarl Ritson       auto MBB = MI->getParent();
211fe5f4c39SCarl Ritson       if (MBB == &MF.back() && MI == &MBB->back())
212fe5f4c39SCarl Ritson         continue;
213fe5f4c39SCarl Ritson 
214fe5f4c39SCarl Ritson       // SI_RETURN_TO_EPILOG is not the last instruction.
215fe5f4c39SCarl Ritson       // Jump to empty block at function end.
216fe5f4c39SCarl Ritson       if (!EmptyMBBAtEnd) {
217fe5f4c39SCarl Ritson         EmptyMBBAtEnd = MF.CreateMachineBasicBlock();
218fe5f4c39SCarl Ritson         MF.insert(MF.end(), EmptyMBBAtEnd);
219fe5f4c39SCarl Ritson       }
220fe5f4c39SCarl Ritson 
221fe5f4c39SCarl Ritson       MBB->addSuccessor(EmptyMBBAtEnd);
2226c9cac5dSCarl Ritson       MDT->getBase().insertEdge(MBB, EmptyMBBAtEnd);
223fe5f4c39SCarl Ritson       BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(AMDGPU::S_BRANCH))
224fe5f4c39SCarl Ritson           .addMBB(EmptyMBBAtEnd);
225fe5f4c39SCarl Ritson       MI->eraseFromParent();
226fe5f4c39SCarl Ritson       MadeChange = true;
227fe5f4c39SCarl Ritson     }
228fe5f4c39SCarl Ritson 
229fe5f4c39SCarl Ritson     EpilogInstrs.clear();
230fe5f4c39SCarl Ritson   }
231fe5f4c39SCarl Ritson 
232fe5f4c39SCarl Ritson   return MadeChange;
233fe5f4c39SCarl Ritson }
234