diff options
Diffstat (limited to 'llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp')
-rw-r--r-- | llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp index 58a9a286e30..f27da92b34f 100644 --- a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp +++ b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp @@ -132,18 +132,86 @@ int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg, // No-op Hazard Detection //===----------------------------------------------------------------------===// +static void addRegsToSet(iterator_range<MachineInstr::const_mop_iterator> Ops, + std::set<unsigned> &Set) { + for (const MachineOperand &Op : Ops) { + if (Op.isReg()) + Set.insert(Op.getReg()); + } +} + +int GCNHazardRecognizer::checkSMEMSoftClauseHazards(MachineInstr *SMEM) { + const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); + + // SMEM soft clause are only present on VI+ + if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS) + return 0; + + // A soft-clause is any group of consecutive SMEM instructions. The + // instructions in this group may return out of order and/or may be + // replayed (i.e. the same instruction issued more than once). + // + // In order to handle these situations correctly we need to make sure + // that when a clause has more than one instruction, no instruction in the + // clause writes to a register that is read another instruction in the clause + // (including itself). If we encounter this situaion, we need to break the + // clause by inserting a non SMEM instruction. + + const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); + std::set<unsigned> ClauseDefs; + std::set<unsigned> ClauseUses; + + for (MachineInstr *MI : EmittedInstrs) { + + // When we hit a non-SMEM instruction then we have passed the start of the + // clause and we can stop. + if (!MI || !TII->isSMRD(*MI)) + break; + + addRegsToSet(MI->defs(), ClauseDefs); + addRegsToSet(MI->uses(), ClauseUses); + } + + if (ClauseDefs.empty()) + return 0; + + // FIXME: When we support stores, we need to make sure not to put loads and + // stores in the same clause if they use the same address. For now, just + // start a new clause whenever we see a store. + if (SMEM->mayStore()) + return 1; + + addRegsToSet(SMEM->defs(), ClauseDefs); + addRegsToSet(SMEM->uses(), ClauseUses); + + std::vector<unsigned> Result(std::max(ClauseDefs.size(), ClauseUses.size())); + std::vector<unsigned>::iterator End; + + End = std::set_intersection(ClauseDefs.begin(), ClauseDefs.end(), + ClauseUses.begin(), ClauseUses.end(), Result.begin()); + + // If the set of defs and uses intersect then we cannot add this instruction + // to the clause, so we have a hazard. + if (End != Result.begin()) + return 1; + + return 0; +} + int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) { const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); + int WaitStatesNeeded = 0; + + WaitStatesNeeded = checkSMEMSoftClauseHazards(SMRD); // This SMRD hazard only affects SI. if (ST.getGeneration() != AMDGPUSubtarget::SOUTHERN_ISLANDS) - return 0; + return WaitStatesNeeded; // A read of an SGPR by SMRD instruction requires 4 wait states when the // SGPR was written by a VALU instruction. int SmrdSgprWaitStates = 4; - int WaitStatesNeeded = 0; auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; for (const MachineOperand &Use : SMRD->uses()) { |