1 //===-- SILateBranchLowering.cpp - Final preparation of branches ----------===//
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 mainly lowers early terminate pseudo instructions.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "AMDGPU.h"
15 #include "GCNSubtarget.h"
16 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
17 #include "SIMachineFunctionInfo.h"
18 #include "llvm/CodeGen/MachineDominators.h"
19 #include "llvm/InitializePasses.h"
20
21 using namespace llvm;
22
23 #define DEBUG_TYPE "si-late-branch-lowering"
24
25 namespace {
26
27 class SILateBranchLowering : public MachineFunctionPass {
28 private:
29 const SIRegisterInfo *TRI = nullptr;
30 const SIInstrInfo *TII = nullptr;
31 MachineDominatorTree *MDT = nullptr;
32
33 void earlyTerm(MachineInstr &MI, MachineBasicBlock *EarlyExitBlock);
34
35 public:
36 static char ID;
37
38 unsigned MovOpc;
39 Register ExecReg;
40
SILateBranchLowering()41 SILateBranchLowering() : MachineFunctionPass(ID) {}
42
43 bool runOnMachineFunction(MachineFunction &MF) override;
44
getPassName() const45 StringRef getPassName() const override {
46 return "SI Final Branch Preparation";
47 }
48
getAnalysisUsage(AnalysisUsage & AU) const49 void getAnalysisUsage(AnalysisUsage &AU) const override {
50 AU.addRequired<MachineDominatorTree>();
51 AU.addPreserved<MachineDominatorTree>();
52 MachineFunctionPass::getAnalysisUsage(AU);
53 }
54 };
55
56 } // end anonymous namespace
57
58 char SILateBranchLowering::ID = 0;
59
60 INITIALIZE_PASS_BEGIN(SILateBranchLowering, DEBUG_TYPE,
61 "SI insert s_cbranch_execz instructions", false, false)
62 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
63 INITIALIZE_PASS_END(SILateBranchLowering, DEBUG_TYPE,
64 "SI insert s_cbranch_execz instructions", false, false)
65
66 char &llvm::SILateBranchLoweringPassID = SILateBranchLowering::ID;
67
generateEndPgm(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,DebugLoc DL,const SIInstrInfo * TII,bool IsPS)68 static void generateEndPgm(MachineBasicBlock &MBB,
69 MachineBasicBlock::iterator I, DebugLoc DL,
70 const SIInstrInfo *TII, bool IsPS) {
71 // "null export"
72 if (IsPS) {
73 BuildMI(MBB, I, DL, TII->get(AMDGPU::EXP_DONE))
74 .addImm(AMDGPU::Exp::ET_NULL)
75 .addReg(AMDGPU::VGPR0, RegState::Undef)
76 .addReg(AMDGPU::VGPR0, RegState::Undef)
77 .addReg(AMDGPU::VGPR0, RegState::Undef)
78 .addReg(AMDGPU::VGPR0, RegState::Undef)
79 .addImm(1) // vm
80 .addImm(0) // compr
81 .addImm(0); // en
82 }
83 // s_endpgm
84 BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ENDPGM)).addImm(0);
85 }
86
splitBlock(MachineBasicBlock & MBB,MachineInstr & MI,MachineDominatorTree * MDT)87 static void splitBlock(MachineBasicBlock &MBB, MachineInstr &MI,
88 MachineDominatorTree *MDT) {
89 MachineBasicBlock *SplitBB = MBB.splitAt(MI, /*UpdateLiveIns*/ true);
90
91 // Update dominator tree
92 using DomTreeT = DomTreeBase<MachineBasicBlock>;
93 SmallVector<DomTreeT::UpdateType, 16> DTUpdates;
94 for (MachineBasicBlock *Succ : SplitBB->successors()) {
95 DTUpdates.push_back({DomTreeT::Insert, SplitBB, Succ});
96 DTUpdates.push_back({DomTreeT::Delete, &MBB, Succ});
97 }
98 DTUpdates.push_back({DomTreeT::Insert, &MBB, SplitBB});
99 MDT->getBase().applyUpdates(DTUpdates);
100 }
101
earlyTerm(MachineInstr & MI,MachineBasicBlock * EarlyExitBlock)102 void SILateBranchLowering::earlyTerm(MachineInstr &MI,
103 MachineBasicBlock *EarlyExitBlock) {
104 MachineBasicBlock &MBB = *MI.getParent();
105 const DebugLoc DL = MI.getDebugLoc();
106
107 auto BranchMI = BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_CBRANCH_SCC0))
108 .addMBB(EarlyExitBlock);
109 auto Next = std::next(MI.getIterator());
110
111 if (Next != MBB.end() && !Next->isTerminator())
112 splitBlock(MBB, *BranchMI, MDT);
113
114 MBB.addSuccessor(EarlyExitBlock);
115 MDT->getBase().insertEdge(&MBB, EarlyExitBlock);
116 }
117
runOnMachineFunction(MachineFunction & MF)118 bool SILateBranchLowering::runOnMachineFunction(MachineFunction &MF) {
119 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
120 TII = ST.getInstrInfo();
121 TRI = &TII->getRegisterInfo();
122 MDT = &getAnalysis<MachineDominatorTree>();
123
124 MovOpc = ST.isWave32() ? AMDGPU::S_MOV_B32 : AMDGPU::S_MOV_B64;
125 ExecReg = ST.isWave32() ? AMDGPU::EXEC_LO : AMDGPU::EXEC;
126
127 SmallVector<MachineInstr *, 4> EarlyTermInstrs;
128 SmallVector<MachineInstr *, 1> EpilogInstrs;
129 bool MadeChange = false;
130
131 for (MachineBasicBlock &MBB : MF) {
132 MachineBasicBlock::iterator I, Next;
133 for (I = MBB.begin(); I != MBB.end(); I = Next) {
134 Next = std::next(I);
135 MachineInstr &MI = *I;
136
137 switch (MI.getOpcode()) {
138 case AMDGPU::S_BRANCH:
139 // Optimize out branches to the next block.
140 // This only occurs in -O0 when BranchFolding is not executed.
141 if (MBB.isLayoutSuccessor(MI.getOperand(0).getMBB())) {
142 assert(&MI == &MBB.back());
143 MI.eraseFromParent();
144 MadeChange = true;
145 }
146 break;
147
148 case AMDGPU::SI_EARLY_TERMINATE_SCC0:
149 EarlyTermInstrs.push_back(&MI);
150 break;
151
152 case AMDGPU::SI_RETURN_TO_EPILOG:
153 EpilogInstrs.push_back(&MI);
154 break;
155
156 default:
157 break;
158 }
159 }
160 }
161
162 // Lower any early exit branches first
163 if (!EarlyTermInstrs.empty()) {
164 MachineBasicBlock *EarlyExitBlock = MF.CreateMachineBasicBlock();
165 DebugLoc DL;
166
167 MF.insert(MF.end(), EarlyExitBlock);
168 BuildMI(*EarlyExitBlock, EarlyExitBlock->end(), DL, TII->get(MovOpc),
169 ExecReg)
170 .addImm(0);
171 generateEndPgm(*EarlyExitBlock, EarlyExitBlock->end(), DL, TII,
172 MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS);
173
174 for (MachineInstr *Instr : EarlyTermInstrs) {
175 // Early termination in GS does nothing
176 if (MF.getFunction().getCallingConv() != CallingConv::AMDGPU_GS)
177 earlyTerm(*Instr, EarlyExitBlock);
178 Instr->eraseFromParent();
179 }
180
181 EarlyTermInstrs.clear();
182 MadeChange = true;
183 }
184
185 // Now check return to epilog instructions occur at function end
186 if (!EpilogInstrs.empty()) {
187 MachineBasicBlock *EmptyMBBAtEnd = nullptr;
188 assert(!MF.getInfo<SIMachineFunctionInfo>()->returnsVoid());
189
190 // If there are multiple returns to epilog then all will
191 // become jumps to new empty end block.
192 if (EpilogInstrs.size() > 1) {
193 EmptyMBBAtEnd = MF.CreateMachineBasicBlock();
194 MF.insert(MF.end(), EmptyMBBAtEnd);
195 }
196
197 for (auto MI : EpilogInstrs) {
198 auto MBB = MI->getParent();
199 if (MBB == &MF.back() && MI == &MBB->back())
200 continue;
201
202 // SI_RETURN_TO_EPILOG is not the last instruction.
203 // Jump to empty block at function end.
204 if (!EmptyMBBAtEnd) {
205 EmptyMBBAtEnd = MF.CreateMachineBasicBlock();
206 MF.insert(MF.end(), EmptyMBBAtEnd);
207 }
208
209 MBB->addSuccessor(EmptyMBBAtEnd);
210 MDT->getBase().insertEdge(MBB, EmptyMBBAtEnd);
211 BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(AMDGPU::S_BRANCH))
212 .addMBB(EmptyMBBAtEnd);
213 MI->eraseFromParent();
214 MadeChange = true;
215 }
216
217 EpilogInstrs.clear();
218 }
219
220 return MadeChange;
221 }
222