1 //===-- GCNHazardRecognizers.cpp - GCN Hazard Recognizer Impls ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements hazard recognizers for scheduling on GCN processors. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "GCNHazardRecognizer.h" 15 #include "AMDGPUSubtarget.h" 16 #include "SIInstrInfo.h" 17 #include "llvm/CodeGen/ScheduleDAG.h" 18 #include "llvm/Support/Debug.h" 19 20 using namespace llvm; 21 22 //===----------------------------------------------------------------------===// 23 // Hazard Recoginizer Implementation 24 //===----------------------------------------------------------------------===// 25 26 GCNHazardRecognizer::GCNHazardRecognizer(const MachineFunction &MF) : 27 CurrCycleInstr(nullptr), 28 MF(MF) { 29 MaxLookAhead = 5; 30 } 31 32 void GCNHazardRecognizer::EmitInstruction(SUnit *SU) { 33 EmitInstruction(SU->getInstr()); 34 } 35 36 void GCNHazardRecognizer::EmitInstruction(MachineInstr *MI) { 37 CurrCycleInstr = MI; 38 } 39 40 ScheduleHazardRecognizer::HazardType 41 GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 42 MachineInstr *MI = SU->getInstr(); 43 44 if (SIInstrInfo::isSMRD(*MI) && checkSMRDHazards(MI) > 0) 45 return NoopHazard; 46 47 if (SIInstrInfo::isVMEM(*MI) && checkVMEMHazards(MI) > 0) 48 return NoopHazard; 49 50 if (SIInstrInfo::isDPP(*MI) && checkDPPHazards(MI) > 0) 51 return NoopHazard; 52 53 return NoHazard; 54 } 55 56 unsigned GCNHazardRecognizer::PreEmitNoops(SUnit *SU) { 57 return PreEmitNoops(SU->getInstr()); 58 } 59 60 unsigned GCNHazardRecognizer::PreEmitNoops(MachineInstr *MI) { 61 if (SIInstrInfo::isSMRD(*MI)) 62 return std::max(0, checkSMRDHazards(MI)); 63 64 if (SIInstrInfo::isVMEM(*MI)) 65 return std::max(0, checkVMEMHazards(MI)); 66 67 if (SIInstrInfo::isDPP(*MI)) 68 return std::max(0, checkDPPHazards(MI)); 69 70 return 0; 71 } 72 73 void GCNHazardRecognizer::EmitNoop() { 74 EmittedInstrs.push_front(nullptr); 75 } 76 77 void GCNHazardRecognizer::AdvanceCycle() { 78 79 // When the scheduler detects a stall, it will call AdvanceCycle() without 80 // emitting any instructions. 81 if (!CurrCycleInstr) 82 return; 83 84 const SIInstrInfo *TII = 85 static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo()); 86 unsigned NumWaitStates = TII->getNumWaitStates(*CurrCycleInstr); 87 88 // Keep track of emitted instructions 89 EmittedInstrs.push_front(CurrCycleInstr); 90 91 // Add a nullptr for each additional wait state after the first. Make sure 92 // not to add more than getMaxLookAhead() items to the list, since we 93 // truncate the list to that size right after this loop. 94 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead()); 95 i < e; ++i) { 96 EmittedInstrs.push_front(nullptr); 97 } 98 99 // getMaxLookahead() is the largest number of wait states we will ever need 100 // to insert, so there is no point in keeping track of more than that many 101 // wait states. 102 EmittedInstrs.resize(getMaxLookAhead()); 103 104 CurrCycleInstr = nullptr; 105 } 106 107 void GCNHazardRecognizer::RecedeCycle() { 108 llvm_unreachable("hazard recognizer does not support bottom-up scheduling."); 109 } 110 111 //===----------------------------------------------------------------------===// 112 // Helper Functions 113 //===----------------------------------------------------------------------===// 114 115 int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg, 116 std::function<bool(MachineInstr*)> IsHazardDef ) { 117 const TargetRegisterInfo *TRI = 118 MF.getSubtarget<AMDGPUSubtarget>().getRegisterInfo(); 119 120 int WaitStates = -1; 121 for (MachineInstr *MI : EmittedInstrs) { 122 ++WaitStates; 123 if (!MI || !IsHazardDef(MI)) 124 continue; 125 if (MI->modifiesRegister(Reg, TRI)) 126 return WaitStates; 127 } 128 return std::numeric_limits<int>::max(); 129 } 130 131 //===----------------------------------------------------------------------===// 132 // No-op Hazard Detection 133 //===----------------------------------------------------------------------===// 134 135 int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) { 136 const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); 137 const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); 138 139 // This SMRD hazard only affects SI. 140 if (ST.getGeneration() != AMDGPUSubtarget::SOUTHERN_ISLANDS) 141 return 0; 142 143 // A read of an SGPR by SMRD instruction requires 4 wait states when the 144 // SGPR was written by a VALU instruction. 145 int SmrdSgprWaitStates = 4; 146 int WaitStatesNeeded = 0; 147 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; 148 149 for (const MachineOperand &Use : SMRD->uses()) { 150 if (!Use.isReg()) 151 continue; 152 int WaitStatesNeededForUse = 153 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); 154 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 155 } 156 return WaitStatesNeeded; 157 } 158 159 int GCNHazardRecognizer::checkVMEMHazards(MachineInstr* VMEM) { 160 const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); 161 const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); 162 163 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS) 164 return 0; 165 166 const SIRegisterInfo &TRI = TII->getRegisterInfo(); 167 168 // A read of an SGPR by a VMEM instruction requires 5 wait states when the 169 // SGPR was written by a VALU Instruction. 170 int VmemSgprWaitStates = 5; 171 int WaitStatesNeeded = 0; 172 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; 173 174 for (const MachineOperand &Use : VMEM->uses()) { 175 if (!Use.isReg() || TRI.isVGPR(MF.getRegInfo(), Use.getReg())) 176 continue; 177 178 int WaitStatesNeededForUse = 179 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); 180 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 181 } 182 return WaitStatesNeeded; 183 } 184 185 int GCNHazardRecognizer::checkDPPHazards(MachineInstr *DPP) { 186 const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); 187 const SIRegisterInfo *TRI = 188 static_cast<const SIRegisterInfo*>(ST.getRegisterInfo()); 189 190 // Check for DPP VGPR read after VALU VGPR write. 191 int DppVgprWaitStates = 2; 192 int WaitStatesNeeded = 0; 193 194 for (const MachineOperand &Use : DPP->uses()) { 195 if (!Use.isReg() || !TRI->isVGPR(MF.getRegInfo(), Use.getReg())) 196 continue; 197 int WaitStatesNeededForUse = 198 DppVgprWaitStates - getWaitStatesSinceDef(Use.getReg()); 199 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 200 } 201 202 return WaitStatesNeeded; 203 } 204