xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/Target/AMDGPU/SILateBranchLowering.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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