forked from OSchip/llvm-project
misched: Initial code for building an MI level scheduling DAG
llvm-svn: 148174
This commit is contained in:
parent
dbee9d8900
commit
59ac4fb706
|
@ -214,22 +214,26 @@ bool MachineSchedulerPass::runOnMachineFunction(MachineFunction &mf) {
|
||||||
// The next region starts above the previous region. Look backward in the
|
// The next region starts above the previous region. Look backward in the
|
||||||
// instruction stream until we find the nearest boundary.
|
// instruction stream until we find the nearest boundary.
|
||||||
MachineBasicBlock::iterator I = RegionEnd;
|
MachineBasicBlock::iterator I = RegionEnd;
|
||||||
for(;I != MBB->begin(); --I) {
|
for(;I != MBB->begin(); --I, --RemainingCount) {
|
||||||
if (TII->isSchedulingBoundary(llvm::prior(I), MBB, *MF))
|
if (TII->isSchedulingBoundary(llvm::prior(I), MBB, *MF))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (I == RegionEnd || I == llvm::prior(RegionEnd)) {
|
if (I == RegionEnd) {
|
||||||
// Skip empty or single instruction scheduling regions.
|
// Skip empty scheduling regions.
|
||||||
RegionEnd = llvm::prior(RegionEnd);
|
RegionEnd = llvm::prior(RegionEnd);
|
||||||
|
--RemainingCount;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DEBUG(dbgs() << "MachineScheduling " << MF->getFunction()->getName()
|
// Schedule regions with more than one instruction.
|
||||||
<< ":BB#" << MBB->getNumber() << "\n From: " << *I << " To: "
|
if (I != llvm::prior(RegionEnd)) {
|
||||||
<< *RegionEnd << " Remaining: " << RemainingCount << "\n");
|
DEBUG(dbgs() << "MachineScheduling " << MF->getFunction()->getName()
|
||||||
|
<< ":BB#" << MBB->getNumber() << "\n From: " << *I << " To: "
|
||||||
|
<< *RegionEnd << " Remaining: " << RemainingCount << "\n");
|
||||||
|
|
||||||
// Inform ScheduleDAGInstrs of the region being scheduler. It calls back
|
// Inform ScheduleDAGInstrs of the region being scheduled. It calls back
|
||||||
// to our Schedule() method.
|
// to our Schedule() method.
|
||||||
Scheduler->Run(MBB, I, RegionEnd, MBB->size());
|
Scheduler->Run(MBB, I, RegionEnd, MBB->size());
|
||||||
|
}
|
||||||
RegionEnd = I;
|
RegionEnd = I;
|
||||||
}
|
}
|
||||||
assert(RemainingCount == 0 && "Instruction count mismatch!");
|
assert(RemainingCount == 0 && "Instruction count mismatch!");
|
||||||
|
|
|
@ -321,7 +321,7 @@ void SUnit::dumpAll(const ScheduleDAG *G) const {
|
||||||
dbgs() << " *";
|
dbgs() << " *";
|
||||||
dbgs() << ": Latency=" << I->getLatency();
|
dbgs() << ": Latency=" << I->getLatency();
|
||||||
if (I->isAssignedRegDep())
|
if (I->isAssignedRegDep())
|
||||||
dbgs() << " Reg=" << G->TRI->getName(I->getReg());
|
dbgs() << " Reg=" << PrintReg(I->getReg());
|
||||||
dbgs() << "\n";
|
dbgs() << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,8 +166,10 @@ void ScheduleDAGInstrs::AddSchedBarrierDeps() {
|
||||||
unsigned Reg = MO.getReg();
|
unsigned Reg = MO.getReg();
|
||||||
if (Reg == 0) continue;
|
if (Reg == 0) continue;
|
||||||
|
|
||||||
assert(TRI->isPhysicalRegister(Reg) && "Virtual register encountered!");
|
if (TRI->isPhysicalRegister(Reg))
|
||||||
Uses[Reg].push_back(&ExitSU);
|
Uses[Reg].push_back(&ExitSU);
|
||||||
|
else
|
||||||
|
assert(!IsPostRA && "Virtual register encountered after regalloc.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For others, e.g. fallthrough, conditional branch, assume the exit
|
// For others, e.g. fallthrough, conditional branch, assume the exit
|
||||||
|
@ -343,11 +345,73 @@ void ScheduleDAGInstrs::addPhysRegDeps(SUnit *SU, unsigned OperIdx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// addVirtRegDeps - Add register dependencies (data, anti, and output) from
|
/// addVRegDefDeps - Add register output and data dependencies from this SUnit
|
||||||
/// this SUnit to following instructions in the same scheduling region that
|
/// to instructions that occur later in the same scheduling region if they read
|
||||||
/// depend the virtual register referenced at OperIdx.
|
/// from or write to the virtual register defined at OperIdx.
|
||||||
void ScheduleDAGInstrs::addVirtRegDeps(SUnit *SU, unsigned OperIdx) {
|
///
|
||||||
assert(false && "unimplemented");
|
/// TODO: Hoist loop induction variable increments. This has to be
|
||||||
|
/// reevaluated. Generally, IV scheduling should be done before coalescing.
|
||||||
|
void ScheduleDAGInstrs::addVRegDefDeps(SUnit *SU, unsigned OperIdx) {
|
||||||
|
const MachineInstr *MI = SU->getInstr();
|
||||||
|
unsigned Reg = MI->getOperand(OperIdx).getReg();
|
||||||
|
|
||||||
|
const TargetSubtargetInfo &ST = TM.getSubtarget<TargetSubtargetInfo>();
|
||||||
|
|
||||||
|
// Add output dependence to the next nearest def of this vreg.
|
||||||
|
//
|
||||||
|
// Unless this definition is dead, the output dependence should be
|
||||||
|
// transitively redundant with antidependencies from this definition's
|
||||||
|
// uses. We're conservative for now until we have a way to guarantee the uses
|
||||||
|
// are not eliminated sometime during scheduling. The output dependence edge
|
||||||
|
// is also useful if output latency exceeds def-use latency.
|
||||||
|
SUnit *DefSU = VRegDefs[Reg];
|
||||||
|
if (DefSU && DefSU != SU && DefSU != &ExitSU) {
|
||||||
|
unsigned OutLatency = TII->getOutputLatency(InstrItins, MI, OperIdx,
|
||||||
|
DefSU->getInstr());
|
||||||
|
DefSU->addPred(SDep(SU, SDep::Output, OutLatency, Reg));
|
||||||
|
}
|
||||||
|
VRegDefs[Reg] = SU;
|
||||||
|
|
||||||
|
// Add data dependence to any uses of this vreg before the next nearest def.
|
||||||
|
//
|
||||||
|
// TODO: Handle ExitSU properly.
|
||||||
|
//
|
||||||
|
// TODO: Data dependence could be handled more efficiently at the use-side.
|
||||||
|
std::vector<SUnit*> &UseList = VRegUses[Reg];
|
||||||
|
for (std::vector<SUnit*>::const_iterator UI = UseList.begin(),
|
||||||
|
UE = UseList.end(); UI != UE; ++UI) {
|
||||||
|
SUnit *UseSU = *UI;
|
||||||
|
if (UseSU == SU) continue;
|
||||||
|
|
||||||
|
// TODO: Handle "special" address latencies cleanly.
|
||||||
|
const SDep& dep = SDep(SU, SDep::Data, SU->Latency, Reg);
|
||||||
|
if (!UnitLatencies) {
|
||||||
|
// Adjust the dependence latency using operand def/use information, then
|
||||||
|
// allow the target to perform its own adjustments.
|
||||||
|
ComputeOperandLatency(SU, UseSU, const_cast<SDep &>(dep));
|
||||||
|
ST.adjustSchedDependency(SU, UseSU, const_cast<SDep &>(dep));
|
||||||
|
}
|
||||||
|
UseSU->addPred(dep);
|
||||||
|
}
|
||||||
|
UseList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// addVRegUseDeps - Add register antidependencies from this SUnit to
|
||||||
|
/// instructions that occur later in the same scheduling region if they
|
||||||
|
/// write the virtual register referenced at OperIdx.
|
||||||
|
void ScheduleDAGInstrs::addVRegUseDeps(SUnit *SU, unsigned OperIdx) {
|
||||||
|
unsigned Reg = SU->getInstr()->getOperand(OperIdx).getReg();
|
||||||
|
|
||||||
|
// Add antidependence to the following def of the vreg it uses.
|
||||||
|
SUnit *DefSU = VRegDefs[Reg];
|
||||||
|
if (DefSU && DefSU != SU)
|
||||||
|
DefSU->addPred(SDep(SU, SDep::Anti, 0, Reg));
|
||||||
|
|
||||||
|
// Add this SUnit to the use list of the vreg it uses.
|
||||||
|
//
|
||||||
|
// TODO: pinch the DAG before we see too many uses to avoid quadratic
|
||||||
|
// behavior. Limiting the scheduling window can accomplish the same thing.
|
||||||
|
VRegUses[Reg].push_back(SU);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
|
void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
|
||||||
|
@ -381,6 +445,15 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
|
||||||
assert(Defs[i].empty() && "Only BuildGraph should push/pop Defs");
|
assert(Defs[i].empty() && "Only BuildGraph should push/pop Defs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reinitialize the large VReg vectors, while reusing the memory.
|
||||||
|
//
|
||||||
|
// Note: this can be an expensive part of DAG building. We may want to be more
|
||||||
|
// clever. Reevaluate after VRegUses goes away.
|
||||||
|
assert(VRegDefs.size() == 0 && VRegUses.size() == 0 &&
|
||||||
|
"Only BuildSchedGraph should access VRegDefs/Uses");
|
||||||
|
VRegDefs.resize(MF.getRegInfo().getNumVirtRegs());
|
||||||
|
VRegUses.resize(MF.getRegInfo().getNumVirtRegs());
|
||||||
|
|
||||||
// Walk the list of instructions, from bottom moving up.
|
// Walk the list of instructions, from bottom moving up.
|
||||||
MachineInstr *PrevMI = NULL;
|
MachineInstr *PrevMI = NULL;
|
||||||
for (MachineBasicBlock::iterator MII = InsertPos, MIE = Begin;
|
for (MachineBasicBlock::iterator MII = InsertPos, MIE = Begin;
|
||||||
|
@ -420,7 +493,10 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
|
||||||
addPhysRegDeps(SU, j);
|
addPhysRegDeps(SU, j);
|
||||||
else {
|
else {
|
||||||
assert(!IsPostRA && "Virtual register encountered!");
|
assert(!IsPostRA && "Virtual register encountered!");
|
||||||
addVirtRegDeps(SU, j);
|
if (MO.isDef())
|
||||||
|
addVRegDefDeps(SU, j);
|
||||||
|
else
|
||||||
|
addVRegUseDeps(SU, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,6 +654,8 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
|
||||||
Defs[i].clear();
|
Defs[i].clear();
|
||||||
Uses[i].clear();
|
Uses[i].clear();
|
||||||
}
|
}
|
||||||
|
VRegDefs.clear();
|
||||||
|
VRegUses.clear();
|
||||||
PendingLoads.clear();
|
PendingLoads.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "llvm/CodeGen/ScheduleDAG.h"
|
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Target/TargetRegisterInfo.h"
|
#include "llvm/Target/TargetRegisterInfo.h"
|
||||||
|
#include "llvm/ADT/IndexedMap.h"
|
||||||
#include "llvm/ADT/SmallSet.h"
|
#include "llvm/ADT/SmallSet.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
@ -107,7 +108,8 @@ namespace llvm {
|
||||||
/// isPostRA flag indicates vregs cannot be present.
|
/// isPostRA flag indicates vregs cannot be present.
|
||||||
bool IsPostRA;
|
bool IsPostRA;
|
||||||
|
|
||||||
/// UnitLatencies flag forces single-cycle data dependencies.
|
/// UnitLatencies (misnamed) flag avoids computing def-use latencies, using
|
||||||
|
/// the def-side latency only.
|
||||||
bool UnitLatencies;
|
bool UnitLatencies;
|
||||||
|
|
||||||
/// Defs, Uses - Remember where defs and uses of each register are as we
|
/// Defs, Uses - Remember where defs and uses of each register are as we
|
||||||
|
@ -117,6 +119,13 @@ namespace llvm {
|
||||||
std::vector<std::vector<SUnit *> > Defs;
|
std::vector<std::vector<SUnit *> > Defs;
|
||||||
std::vector<std::vector<SUnit *> > Uses;
|
std::vector<std::vector<SUnit *> > Uses;
|
||||||
|
|
||||||
|
// Virtual register Defs and Uses.
|
||||||
|
//
|
||||||
|
// TODO: Eliminate VRegUses by creating SUnits in a prepass and looking up
|
||||||
|
// the live range's reaching def.
|
||||||
|
IndexedMap<SUnit*, VirtReg2IndexFunctor> VRegDefs;
|
||||||
|
IndexedMap<std::vector<SUnit*>, VirtReg2IndexFunctor> VRegUses;
|
||||||
|
|
||||||
/// PendingLoads - Remember where unknown loads are after the most recent
|
/// PendingLoads - Remember where unknown loads are after the most recent
|
||||||
/// unknown store, as we iterate. As with Defs and Uses, this is here
|
/// unknown store, as we iterate. As with Defs and Uses, this is here
|
||||||
/// to minimize construction/destruction.
|
/// to minimize construction/destruction.
|
||||||
|
@ -211,7 +220,8 @@ namespace llvm {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void addPhysRegDeps(SUnit *SU, unsigned OperIdx);
|
void addPhysRegDeps(SUnit *SU, unsigned OperIdx);
|
||||||
void addVirtRegDeps(SUnit *SU, unsigned OperIdx);
|
void addVRegDefDeps(SUnit *SU, unsigned OperIdx);
|
||||||
|
void addVRegUseDeps(SUnit *SU, unsigned OperIdx);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue