Home | History | Annotate | Line # | Download | only in AMDGPU
      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 
     41   SILateBranchLowering() : MachineFunctionPass(ID) {}
     42 
     43   bool runOnMachineFunction(MachineFunction &MF) override;
     44 
     45   StringRef getPassName() const override {
     46     return "SI Final Branch Preparation";
     47   }
     48 
     49   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 
     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 
     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 
    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 
    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