aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAndrew Trick <atrick@apple.com>2012-01-14 02:17:18 +0000
committerAndrew Trick <atrick@apple.com>2012-01-14 02:17:18 +0000
commit3c58ba8ea7ec097d69d7f7be5930a4a4d7405a18 (patch)
treea592a9ac079d5b83db6022a5b20e4ca74dabfa66 /lib
parent7ebcaf4cf929ef041ae6c9c07b897e4d0aa8ad06 (diff)
downloadexternal_llvm-3c58ba8ea7ec097d69d7f7be5930a4a4d7405a18.zip
external_llvm-3c58ba8ea7ec097d69d7f7be5930a4a4d7405a18.tar.gz
external_llvm-3c58ba8ea7ec097d69d7f7be5930a4a4d7405a18.tar.bz2
misched: Initial code for building an MI level scheduling DAG
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@148174 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/MachineScheduler.cpp24
-rw-r--r--lib/CodeGen/ScheduleDAG.cpp2
-rw-r--r--lib/CodeGen/ScheduleDAGInstrs.cpp94
-rw-r--r--lib/CodeGen/ScheduleDAGInstrs.h14
4 files changed, 113 insertions, 21 deletions
diff --git a/lib/CodeGen/MachineScheduler.cpp b/lib/CodeGen/MachineScheduler.cpp
index e6ca0e8..df706cb 100644
--- a/lib/CodeGen/MachineScheduler.cpp
+++ b/lib/CodeGen/MachineScheduler.cpp
@@ -214,22 +214,26 @@ bool MachineSchedulerPass::runOnMachineFunction(MachineFunction &mf) {
// The next region starts above the previous region. Look backward in the
// instruction stream until we find the nearest boundary.
MachineBasicBlock::iterator I = RegionEnd;
- for(;I != MBB->begin(); --I) {
+ for(;I != MBB->begin(); --I, --RemainingCount) {
if (TII->isSchedulingBoundary(llvm::prior(I), MBB, *MF))
break;
}
- if (I == RegionEnd || I == llvm::prior(RegionEnd)) {
- // Skip empty or single instruction scheduling regions.
+ if (I == RegionEnd) {
+ // Skip empty scheduling regions.
RegionEnd = llvm::prior(RegionEnd);
+ --RemainingCount;
continue;
}
- 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
- // to our Schedule() method.
- Scheduler->Run(MBB, I, RegionEnd, MBB->size());
+ // Schedule regions with more than one instruction.
+ if (I != llvm::prior(RegionEnd)) {
+ DEBUG(dbgs() << "MachineScheduling " << MF->getFunction()->getName()
+ << ":BB#" << MBB->getNumber() << "\n From: " << *I << " To: "
+ << *RegionEnd << " Remaining: " << RemainingCount << "\n");
+
+ // Inform ScheduleDAGInstrs of the region being scheduled. It calls back
+ // to our Schedule() method.
+ Scheduler->Run(MBB, I, RegionEnd, MBB->size());
+ }
RegionEnd = I;
}
assert(RemainingCount == 0 && "Instruction count mismatch!");
diff --git a/lib/CodeGen/ScheduleDAG.cpp b/lib/CodeGen/ScheduleDAG.cpp
index e829668..f92c72a 100644
--- a/lib/CodeGen/ScheduleDAG.cpp
+++ b/lib/CodeGen/ScheduleDAG.cpp
@@ -321,7 +321,7 @@ void SUnit::dumpAll(const ScheduleDAG *G) const {
dbgs() << " *";
dbgs() << ": Latency=" << I->getLatency();
if (I->isAssignedRegDep())
- dbgs() << " Reg=" << G->TRI->getName(I->getReg());
+ dbgs() << " Reg=" << PrintReg(I->getReg());
dbgs() << "\n";
}
}
diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp
index 955fcc9..b334920 100644
--- a/lib/CodeGen/ScheduleDAGInstrs.cpp
+++ b/lib/CodeGen/ScheduleDAGInstrs.cpp
@@ -166,8 +166,10 @@ void ScheduleDAGInstrs::AddSchedBarrierDeps() {
unsigned Reg = MO.getReg();
if (Reg == 0) continue;
- assert(TRI->isPhysicalRegister(Reg) && "Virtual register encountered!");
- Uses[Reg].push_back(&ExitSU);
+ if (TRI->isPhysicalRegister(Reg))
+ Uses[Reg].push_back(&ExitSU);
+ else
+ assert(!IsPostRA && "Virtual register encountered after regalloc.");
}
} else {
// 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
-/// this SUnit to following instructions in the same scheduling region that
-/// depend the virtual register referenced at OperIdx.
-void ScheduleDAGInstrs::addVirtRegDeps(SUnit *SU, unsigned OperIdx) {
- assert(false && "unimplemented");
+/// addVRegDefDeps - Add register output and data dependencies from this SUnit
+/// to instructions that occur later in the same scheduling region if they read
+/// from or write to the virtual register defined at OperIdx.
+///
+/// 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) {
@@ -381,6 +445,15 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
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.
MachineInstr *PrevMI = NULL;
for (MachineBasicBlock::iterator MII = InsertPos, MIE = Begin;
@@ -420,7 +493,10 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
addPhysRegDeps(SU, j);
else {
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();
Uses[i].clear();
}
+ VRegDefs.clear();
+ VRegUses.clear();
PendingLoads.clear();
}
diff --git a/lib/CodeGen/ScheduleDAGInstrs.h b/lib/CodeGen/ScheduleDAGInstrs.h
index 55da5c0..1718364 100644
--- a/lib/CodeGen/ScheduleDAGInstrs.h
+++ b/lib/CodeGen/ScheduleDAGInstrs.h
@@ -20,6 +20,7 @@
#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/SmallSet.h"
#include <map>
@@ -107,7 +108,8 @@ namespace llvm {
/// isPostRA flag indicates vregs cannot be present.
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;
/// 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 *> > 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
/// unknown store, as we iterate. As with Defs and Uses, this is here
/// to minimize construction/destruction.
@@ -211,7 +220,8 @@ namespace llvm {
protected:
void addPhysRegDeps(SUnit *SU, unsigned OperIdx);
- void addVirtRegDeps(SUnit *SU, unsigned OperIdx);
+ void addVRegDefDeps(SUnit *SU, unsigned OperIdx);
+ void addVRegUseDeps(SUnit *SU, unsigned OperIdx);
};
}