Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AMDGPU/SI: Enable the post-ra scheduler
Summary: This includes a hazard recognizer implementation to replace some of the hazard handling we had during frame index elimination. Reviewers: arsenm Subscribers: qcolombet, arsenm, llvm-commits Differential Revision: http://reviews.llvm.org/D18602 llvm-svn: 268143
- Loading branch information
1 parent
52c68bb
commit cb6ba62
Showing
35 changed files
with
426 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
//===-- GCNHazardRecognizers.cpp - GCN Hazard Recognizer Impls ------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file implements hazard recognizers for scheduling on GCN processors. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "GCNHazardRecognizer.h" | ||
#include "AMDGPUSubtarget.h" | ||
#include "SIInstrInfo.h" | ||
#include "llvm/CodeGen/ScheduleDAG.h" | ||
#include "llvm/Support/Debug.h" | ||
|
||
using namespace llvm; | ||
|
||
//===----------------------------------------------------------------------===// | ||
// Hazard Recoginizer Implementation | ||
//===----------------------------------------------------------------------===// | ||
|
||
GCNHazardRecognizer::GCNHazardRecognizer(const MachineFunction &MF) : | ||
CurrCycleInstr(nullptr), | ||
MF(MF) { | ||
MaxLookAhead = 5; | ||
} | ||
|
||
void GCNHazardRecognizer::EmitInstruction(SUnit *SU) { | ||
EmitInstruction(SU->getInstr()); | ||
} | ||
|
||
void GCNHazardRecognizer::EmitInstruction(MachineInstr *MI) { | ||
CurrCycleInstr = MI; | ||
} | ||
|
||
ScheduleHazardRecognizer::HazardType | ||
GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { | ||
const SIInstrInfo *TII = | ||
static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo()); | ||
MachineInstr *MI = SU->getInstr(); | ||
|
||
if (TII->isSMRD(*MI) && checkSMRDHazards(MI) > 0) | ||
return NoopHazard; | ||
|
||
if (TII->isVMEM(*MI) && checkVMEMHazards(MI) > 0) | ||
return NoopHazard; | ||
|
||
return NoHazard; | ||
} | ||
|
||
unsigned GCNHazardRecognizer::PreEmitNoops(SUnit *SU) { | ||
return PreEmitNoops(SU->getInstr()); | ||
} | ||
|
||
unsigned GCNHazardRecognizer::PreEmitNoops(MachineInstr *MI) { | ||
const SIInstrInfo *TII = | ||
static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo()); | ||
|
||
if (TII->isSMRD(*MI)) | ||
return std::max(0, checkSMRDHazards(MI)); | ||
|
||
if (TII->isVMEM(*MI)) | ||
return std::max(0, checkVMEMHazards(MI)); | ||
|
||
return 0; | ||
} | ||
|
||
void GCNHazardRecognizer::EmitNoop() { | ||
EmittedInstrs.push_front(nullptr); | ||
} | ||
|
||
void GCNHazardRecognizer::AdvanceCycle() { | ||
|
||
// When the scheduler detects a stall, it will call AdvanceCycle() without | ||
// emitting any instructions. | ||
if (!CurrCycleInstr) | ||
return; | ||
|
||
const SIInstrInfo *TII = | ||
static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo()); | ||
unsigned NumWaitStates = TII->getNumWaitStates(*CurrCycleInstr); | ||
|
||
// Keep track of emitted instructions | ||
EmittedInstrs.push_front(CurrCycleInstr); | ||
|
||
// Add a nullptr for each additional wait state after the first. Make sure | ||
// not to add more than getMaxLookAhead() items to the list, since we | ||
// truncate the list to that size right after this loop. | ||
for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead()); | ||
i < e; ++i) { | ||
EmittedInstrs.push_front(nullptr); | ||
} | ||
|
||
// getMaxLookahead() is the largest number of wait states we will ever need | ||
// to insert, so there is no point in keeping track of more than that many | ||
// wait states. | ||
EmittedInstrs.resize(getMaxLookAhead()); | ||
|
||
CurrCycleInstr = nullptr; | ||
} | ||
|
||
void GCNHazardRecognizer::RecedeCycle() { | ||
llvm_unreachable("hazard recognizer does not support bottom-up scheduling."); | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
// Helper Functions | ||
//===----------------------------------------------------------------------===// | ||
|
||
int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg, | ||
std::function<bool(MachineInstr*)> IsHazardDef ) { | ||
const TargetRegisterInfo *TRI = | ||
MF.getSubtarget<AMDGPUSubtarget>().getRegisterInfo(); | ||
|
||
int WaitStates = -1; | ||
for (MachineInstr *MI : EmittedInstrs) { | ||
++WaitStates; | ||
if (!MI || !IsHazardDef(MI)) | ||
continue; | ||
if (MI->modifiesRegister(Reg, TRI)) | ||
return WaitStates; | ||
} | ||
return std::numeric_limits<int>::max(); | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
// No-op Hazard Detection | ||
//===----------------------------------------------------------------------===// | ||
|
||
int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) { | ||
const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); | ||
const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); | ||
|
||
// This SMRD hazard only affects SI. | ||
if (ST.getGeneration() != AMDGPUSubtarget::SOUTHERN_ISLANDS) | ||
return 0; | ||
|
||
// 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()) { | ||
if (!Use.isReg()) | ||
continue; | ||
int WaitStatesNeededForUse = | ||
SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); | ||
WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); | ||
} | ||
return WaitStatesNeeded; | ||
} | ||
|
||
int GCNHazardRecognizer::checkVMEMHazards(MachineInstr* VMEM) { | ||
const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>(); | ||
const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); | ||
|
||
if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS) | ||
return 0; | ||
|
||
const SIRegisterInfo &TRI = TII->getRegisterInfo(); | ||
|
||
// A read of an SGPR by a VMEM instruction requires 5 wait states when the | ||
// SGPR was written by a VALU Instruction. | ||
int VmemSgprWaitStates = 5; | ||
int WaitStatesNeeded = 0; | ||
auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; | ||
|
||
for (const MachineOperand &Use : VMEM->uses()) { | ||
if (!Use.isReg() || TRI.isVGPR(MF.getRegInfo(), Use.getReg())) | ||
continue; | ||
|
||
int WaitStatesNeededForUse = | ||
VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); | ||
WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); | ||
} | ||
return WaitStatesNeeded; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
//===-- GCNHazardRecognizers.h - GCN Hazard Recognizers ---------*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file defines hazard recognizers for scheduling on GCN processors. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_LIB_TARGET_AMDGPUHAZARDRECOGNIZERS_H | ||
#define LLVM_LIB_TARGET_AMDGPUHAZARDRECOGNIZERS_H | ||
|
||
#include "llvm/CodeGen/ScheduleHazardRecognizer.h" | ||
#include <functional> | ||
#include <list> | ||
|
||
namespace llvm { | ||
|
||
class MachineFunction; | ||
class MachineInstr; | ||
class ScheduleDAG; | ||
class SIInstrInfo; | ||
|
||
class GCNHazardRecognizer final : public ScheduleHazardRecognizer { | ||
|
||
// This variable stores the instruction that has been emitted this cycle. | ||
// It will be added to EmittedInstrs, when AdvanceCycle() or RecedeCycle() is | ||
// called. | ||
MachineInstr *CurrCycleInstr; | ||
std::list<MachineInstr*> EmittedInstrs; | ||
const MachineFunction &MF; | ||
|
||
int getWaitStatesSinceDef(unsigned Reg, | ||
std::function<bool(MachineInstr*)> IsHazardDef = | ||
[](MachineInstr*) {return true;}); | ||
|
||
int checkSMRDHazards(MachineInstr *SMRD); | ||
int checkVMEMHazards(MachineInstr* VMEM); | ||
public: | ||
GCNHazardRecognizer(const MachineFunction &MF); | ||
// We can only issue one instruction per cycle. | ||
bool atIssueLimit() const override { return true; } | ||
void EmitInstruction(SUnit *SU) override; | ||
void EmitInstruction(MachineInstr *MI) override; | ||
HazardType getHazardType(SUnit *SU, int Stalls) override; | ||
void EmitNoop() override; | ||
unsigned PreEmitNoops(SUnit *SU) override; | ||
unsigned PreEmitNoops(MachineInstr *) override; | ||
void AdvanceCycle() override; | ||
void RecedeCycle() override; | ||
}; | ||
|
||
} // end namespace llvm | ||
|
||
#endif //LLVM_LIB_TARGET_AMDGPUHAZARDRECOGNIZERS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.