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 const SIInstrInfo *TII = 43 static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo()); 44 MachineInstr *MI = SU->getInstr(); 45 46 if (TII->isSMRD(*MI) && checkSMRDHazards(MI) > 0) 47 return NoopHazard; 48 49 if (TII->isVMEM(*MI) && checkVMEMHazards(MI) > 0) 50 return NoopHazard; 51 52 return NoHazard; 53 } 54 55 unsigned GCNHazardRecognizer::PreEmitNoops(SUnit *SU) { 56 return PreEmitNoops(SU->getInstr()); 57 } 58 59 unsigned GCNHazardRecognizer::PreEmitNoops(MachineInstr *MI) { 60 const SIInstrInfo *TII = 61 static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo()); 62 63 if (TII->isSMRD(*MI)) 64 return std::max(0, checkSMRDHazards(MI)); 65 66 if (TII->isVMEM(*MI)) 67 return std::max(0, checkVMEMHazards(MI)); 68 69 return 0; 70 } 71 72 void GCNHazardRecognizer::EmitNoop() { 73 EmittedInstrs.push_front(nullptr); 74 } 75 76 void GCNHazardRecognizer::AdvanceCycle() { 77 78 // When the scheduler detects a stall, it will call AdvanceCycle() without 79 // emitting any instructions. 80 if (!CurrCycleInstr) 81 return; 82 83 const SIInstrInfo *TII = 84 static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo()); 85 unsigned NumWaitStates = TII->getNumWaitStates(*CurrCycleInstr); 86 87 // Keep track of emitted instructions 88 EmittedInstrs.push_front(CurrCycleInstr); 89 90 // Add a nullptr for each additional wait state after the first. Make sure 91 // not to add more than getMaxLookAhead() items to the list, since we 92 // truncate the list to that size right after this loop. 93 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead()); 94 i < e; ++i) { 95 EmittedInstrs.push_front(nullptr); 96 } 97 98 // getMaxLookahead() is the largest number of wait states we will ever need 99 // to insert, so there is no point in keeping track of more than that many 100 // wait states. 101 EmittedInstrs.resize(getMaxLookAhead()); 102 103 CurrCycleInstr = nullptr; 104 } 105 106 void GCNHazardRecognizer::RecedeCycle() { 107 llvm_unreachable("hazard recognizer does not support bottom-up scheduling."); 108 } 109 110 //===----------------------------------------------------------------------===// 111 // Helper Functions 112 //===----------------------------------------------------------------------===// 113 114 int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg, 115 std::function<bool(MachineInstr*)> IsHazardDef ) { 116 const TargetRegisterInfo *TRI = 117 MF.getSubtarget<AMDGPUSubtarget>().getRegisterInfo(); 118 119 int WaitStates = -1; 120 for (MachineInstr *MI : EmittedInstrs) { 121 ++WaitStates; 122 if (!MI || !IsHazardDef(MI)) 123 continue; 124 if (MI->modifiesRegister(Reg, TRI)) 125 return WaitStates; 126 } 127 return std::numeric_limits<int>::max(); 128 } 129 130 //===----------------------------------------------------------------------===// 131 // No-op Hazard Detection 132 //===----------------------------------------------------------------------===// 133 134 int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) { 135 const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); 136 const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); 137 138 // This SMRD hazard only affects SI. 139 if (ST.getGeneration() != AMDGPUSubtarget::SOUTHERN_ISLANDS) 140 return 0; 141 142 // A read of an SGPR by SMRD instruction requires 4 wait states when the 143 // SGPR was written by a VALU instruction. 144 int SmrdSgprWaitStates = 4; 145 int WaitStatesNeeded = 0; 146 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; 147 148 for (const MachineOperand &Use : SMRD->uses()) { 149 if (!Use.isReg()) 150 continue; 151 int WaitStatesNeededForUse = 152 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); 153 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 154 } 155 return WaitStatesNeeded; 156 } 157 158 int GCNHazardRecognizer::checkVMEMHazards(MachineInstr* VMEM) { 159 const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); 160 const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); 161 162 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS) 163 return 0; 164 165 const SIRegisterInfo &TRI = TII->getRegisterInfo(); 166 167 // A read of an SGPR by a VMEM instruction requires 5 wait states when the 168 // SGPR was written by a VALU Instruction. 169 int VmemSgprWaitStates = 5; 170 int WaitStatesNeeded = 0; 171 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; 172 173 for (const MachineOperand &Use : VMEM->uses()) { 174 if (!Use.isReg() || TRI.isVGPR(MF.getRegInfo(), Use.getReg())) 175 continue; 176 177 int WaitStatesNeededForUse = 178 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); 179 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 180 } 181 return WaitStatesNeeded; 182 } 183