1 //===-- SIPreEmitPeephole.cpp ------------------------------------===// 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 performs the peephole optimizations before code emission. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "AMDGPU.h" 15 #include "AMDGPUSubtarget.h" 16 #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 17 #include "SIInstrInfo.h" 18 #include "llvm/CodeGen/MachineFunctionPass.h" 19 #include "llvm/Support/CommandLine.h" 20 21 using namespace llvm; 22 23 #define DEBUG_TYPE "si-pre-emit-peephole" 24 25 namespace { 26 27 class SIPreEmitPeephole : public MachineFunctionPass { 28 private: 29 const SIInstrInfo *TII = nullptr; 30 const SIRegisterInfo *TRI = nullptr; 31 32 bool optimizeVccBranch(MachineInstr &MI) const; 33 34 public: 35 static char ID; 36 37 SIPreEmitPeephole() : MachineFunctionPass(ID) { 38 initializeSIPreEmitPeepholePass(*PassRegistry::getPassRegistry()); 39 } 40 41 bool runOnMachineFunction(MachineFunction &MF) override; 42 }; 43 44 } // End anonymous namespace. 45 46 INITIALIZE_PASS(SIPreEmitPeephole, DEBUG_TYPE, 47 "SI peephole optimizations", false, false) 48 49 char SIPreEmitPeephole::ID = 0; 50 51 char &llvm::SIPreEmitPeepholeID = SIPreEmitPeephole::ID; 52 53 bool SIPreEmitPeephole::optimizeVccBranch(MachineInstr &MI) const { 54 // Match: 55 // sreg = -1 56 // vcc = S_AND_B64 exec, sreg 57 // S_CBRANCH_VCC[N]Z 58 // => 59 // S_CBRANCH_EXEC[N]Z 60 // We end up with this pattern sometimes after basic block placement. 61 // It happens while combining a block which assigns -1 to a saved mask and 62 // another block which consumes that saved mask and then a branch. 63 bool Changed = false; 64 MachineBasicBlock &MBB = *MI.getParent(); 65 const GCNSubtarget &ST = MBB.getParent()->getSubtarget<GCNSubtarget>(); 66 const bool IsWave32 = ST.isWave32(); 67 const unsigned CondReg = TRI->getVCC(); 68 const unsigned ExecReg = IsWave32 ? AMDGPU::EXEC_LO : AMDGPU::EXEC; 69 const unsigned And = IsWave32 ? AMDGPU::S_AND_B32 : AMDGPU::S_AND_B64; 70 71 MachineBasicBlock::reverse_iterator A = MI.getReverseIterator(), 72 E = MBB.rend(); 73 bool ReadsCond = false; 74 unsigned Threshold = 5; 75 for (++A; A != E; ++A) { 76 if (!--Threshold) 77 return false; 78 if (A->modifiesRegister(ExecReg, TRI)) 79 return false; 80 if (A->modifiesRegister(CondReg, TRI)) { 81 if (!A->definesRegister(CondReg, TRI) || A->getOpcode() != And) 82 return false; 83 break; 84 } 85 ReadsCond |= A->readsRegister(CondReg, TRI); 86 } 87 if (A == E) 88 return false; 89 90 MachineOperand &Op1 = A->getOperand(1); 91 MachineOperand &Op2 = A->getOperand(2); 92 if (Op1.getReg() != ExecReg && Op2.isReg() && Op2.getReg() == ExecReg) { 93 TII->commuteInstruction(*A); 94 Changed = true; 95 } 96 if (Op1.getReg() != ExecReg) 97 return Changed; 98 if (Op2.isImm() && Op2.getImm() != -1) 99 return Changed; 100 101 Register SReg; 102 if (Op2.isReg()) { 103 SReg = Op2.getReg(); 104 auto M = std::next(A); 105 bool ReadsSreg = false; 106 for (; M != E; ++M) { 107 if (M->definesRegister(SReg, TRI)) 108 break; 109 if (M->modifiesRegister(SReg, TRI)) 110 return Changed; 111 ReadsSreg |= M->readsRegister(SReg, TRI); 112 } 113 if (M == E || !M->isMoveImmediate() || !M->getOperand(1).isImm() || 114 M->getOperand(1).getImm() != -1) 115 return Changed; 116 // First if sreg is only used in and instruction fold the immediate 117 // into that and. 118 if (!ReadsSreg && Op2.isKill()) { 119 A->getOperand(2).ChangeToImmediate(-1); 120 M->eraseFromParent(); 121 } 122 } 123 124 if (!ReadsCond && A->registerDefIsDead(AMDGPU::SCC) && 125 MI.killsRegister(CondReg, TRI)) 126 A->eraseFromParent(); 127 128 bool IsVCCZ = MI.getOpcode() == AMDGPU::S_CBRANCH_VCCZ; 129 if (SReg == ExecReg) { 130 if (IsVCCZ) { 131 MI.eraseFromParent(); 132 return true; 133 } 134 MI.setDesc(TII->get(AMDGPU::S_BRANCH)); 135 } else { 136 MI.setDesc( 137 TII->get(IsVCCZ ? AMDGPU::S_CBRANCH_EXECZ : AMDGPU::S_CBRANCH_EXECNZ)); 138 } 139 140 MI.RemoveOperand(MI.findRegisterUseOperandIdx(CondReg, false /*Kill*/, TRI)); 141 MI.addImplicitDefUseOperands(*MBB.getParent()); 142 143 return true; 144 } 145 146 bool SIPreEmitPeephole::runOnMachineFunction(MachineFunction &MF) { 147 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 148 TII = ST.getInstrInfo(); 149 TRI = &TII->getRegisterInfo(); 150 bool Changed = false; 151 152 for (MachineBasicBlock &MBB : MF) { 153 MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); 154 if (MBBI == MBB.end()) 155 continue; 156 157 MachineInstr &MI = *MBBI; 158 switch (MI.getOpcode()) { 159 case AMDGPU::S_CBRANCH_VCCZ: 160 case AMDGPU::S_CBRANCH_VCCNZ: 161 Changed |= optimizeVccBranch(MI); 162 break; 163 default: 164 break; 165 } 166 } 167 168 return Changed; 169 } 170