Newer
Older
//===- MachineScheduler.cpp - Machine Instruction Scheduler ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// MachineScheduler schedules machine instructions after phi elimination. It
// preserves LiveIntervals so it can be invoked before register allocation.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "misched"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachinePassRegistry.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
#include "llvm/Analysis/AliasAnalysis.h"
Andrew Trick
committed
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/OwningPtr.h"
Andrew Trick
committed
#include <queue>
#ifndef NDEBUG
static cl::opt<bool> ViewMISchedDAGs("view-misched-dags", cl::Hidden,
cl::desc("Pop up a window to show MISched dags after they are processed"));
#else
static bool ViewMISchedDAGs = false;
#endif // NDEBUG
Andrew Trick
committed
//===----------------------------------------------------------------------===//
// Machine Instruction Scheduling Pass and Registry
//===----------------------------------------------------------------------===//
/// MachineScheduler runs after coalescing and before register allocation.
class MachineScheduler : public MachineFunctionPass {
Andrew Trick
committed
const TargetInstrInfo *TII;
const MachineLoopInfo *MLI;
const MachineDominatorTree *MDT;
Lang Hames
committed
LiveIntervals *LIS;
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
virtual void releaseMemory() {}
virtual bool runOnMachineFunction(MachineFunction&);
virtual void print(raw_ostream &O, const Module* = 0) const;
static char ID; // Class identification, replacement for typeinfo
};
} // namespace
char MachineScheduler::ID = 0;
char &llvm::MachineSchedulerID = MachineScheduler::ID;
INITIALIZE_PASS_BEGIN(MachineScheduler, "misched",
"Machine Instruction Scheduler", false, false)
INITIALIZE_AG_DEPENDENCY(AliasAnalysis)
INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_END(MachineScheduler, "misched",
"Machine Instruction Scheduler", false, false)
MachineScheduler::MachineScheduler()
: MachineFunctionPass(ID), MF(0), MLI(0), MDT(0) {
initializeMachineSchedulerPass(*PassRegistry::getPassRegistry());
void MachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequiredID(MachineDominatorsID);
AU.addRequired<MachineLoopInfo>();
AU.addRequired<AliasAnalysis>();
AU.addPreserved<AliasAnalysis>();
AU.addRequired<SlotIndexes>();
AU.addPreserved<SlotIndexes>();
AU.addRequired<LiveIntervals>();
AU.addPreserved<LiveIntervals>();
MachineFunctionPass::getAnalysisUsage(AU);
}
namespace {
/// MachineSchedRegistry provides a selection of available machine instruction
/// schedulers.
class MachineSchedRegistry : public MachinePassRegistryNode {
public:
typedef ScheduleDAGInstrs *(*ScheduleDAGCtor)(MachineScheduler *);
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// RegisterPassParser requires a (misnamed) FunctionPassCtor type.
typedef ScheduleDAGCtor FunctionPassCtor;
static MachinePassRegistry Registry;
MachineSchedRegistry(const char *N, const char *D, ScheduleDAGCtor C)
: MachinePassRegistryNode(N, D, (MachinePassCtor)C) {
Registry.Add(this);
}
~MachineSchedRegistry() { Registry.Remove(this); }
// Accessors.
//
MachineSchedRegistry *getNext() const {
return (MachineSchedRegistry *)MachinePassRegistryNode::getNext();
}
static MachineSchedRegistry *getList() {
return (MachineSchedRegistry *)Registry.getList();
}
static ScheduleDAGCtor getDefault() {
return (ScheduleDAGCtor)Registry.getDefault();
}
static void setDefault(ScheduleDAGCtor C) {
Registry.setDefault((MachinePassCtor)C);
}
static void setListener(MachinePassRegistryListener *L) {
Registry.setListener(L);
}
};
} // namespace
MachinePassRegistry MachineSchedRegistry::Registry;
static ScheduleDAGInstrs *createDefaultMachineSched(MachineScheduler *P);
/// MachineSchedOpt allows command line selection of the scheduler.
static cl::opt<MachineSchedRegistry::ScheduleDAGCtor, false,
RegisterPassParser<MachineSchedRegistry> >
MachineSchedOpt("misched",
cl::init(&createDefaultMachineSched), cl::Hidden,
cl::desc("Machine instruction scheduler to use"));
Andrew Trick
committed
//===----------------------------------------------------------------------===//
// Machine Instruction Scheduling Common Implementation
Andrew Trick
committed
//===----------------------------------------------------------------------===//
namespace {
/// ScheduleTopDownLive is an implementation of ScheduleDAGInstrs that schedules
Andrew Trick
committed
/// machine instructions while updating LiveIntervals.
class ScheduleTopDownLive : public ScheduleDAGInstrs {
protected:
MachineScheduler *Pass;
Andrew Trick
committed
public:
ScheduleTopDownLive(MachineScheduler *P):
ScheduleDAGInstrs(*P->MF, *P->MLI, *P->MDT, /*IsPostRA=*/false, P->LIS),
Pass(P) {}
Andrew Trick
committed
/// ScheduleDAGInstrs callback.
void schedule();
Andrew Trick
committed
/// Interface implemented by the selected top-down liveinterval scheduler.
///
/// Pick the next node to schedule, or return NULL.
virtual SUnit *pickNode() = 0;
/// When all preceeding dependencies have been resolved, free this node for
/// scheduling.
virtual void releaseNode(SUnit *SU) = 0;
protected:
void releaseSucc(SUnit *SU, SDep *SuccEdge);
void releaseSuccessors(SUnit *SU);
Andrew Trick
committed
};
} // namespace
Andrew Trick
committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/// ReleaseSucc - Decrement the NumPredsLeft count of a successor. When
/// NumPredsLeft reaches zero, release the successor node.
void ScheduleTopDownLive::releaseSucc(SUnit *SU, SDep *SuccEdge) {
SUnit *SuccSU = SuccEdge->getSUnit();
#ifndef NDEBUG
if (SuccSU->NumPredsLeft == 0) {
dbgs() << "*** Scheduling failed! ***\n";
SuccSU->dump(this);
dbgs() << " has been released too many times!\n";
llvm_unreachable(0);
}
#endif
--SuccSU->NumPredsLeft;
if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU)
releaseNode(SuccSU);
}
/// releaseSuccessors - Call releaseSucc on each of SU's successors.
void ScheduleTopDownLive::releaseSuccessors(SUnit *SU) {
for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
I != E; ++I) {
releaseSucc(SU, &*I);
}
}
/// schedule - This is called back from ScheduleDAGInstrs::Run() when it's
Andrew Trick
committed
/// time to do some work.
void ScheduleTopDownLive::schedule() {
buildSchedGraph(&Pass->getAnalysis<AliasAnalysis>());
Andrew Trick
committed
DEBUG(dbgs() << "********** MI Scheduling **********\n");
DEBUG(for (unsigned su = 0, e = SUnits.size(); su != e; ++su)
SUnits[su].dumpAll(this));
Andrew Trick
committed
// Release any successors of the special Entry node. It is currently unused,
// but we keep up appearances.
releaseSuccessors(&EntrySU);
// Release all DAG roots for scheduling.
for (std::vector<SUnit>::iterator I = SUnits.begin(), E = SUnits.end();
I != E; ++I) {
// A SUnit is ready to schedule if it has no predecessors.
if (I->Preds.empty())
releaseNode(&(*I));
}
MachineBasicBlock::iterator InsertPos = Begin;
Andrew Trick
committed
while (SUnit *SU = pickNode()) {
DEBUG(dbgs() << "*** Scheduling Instruction:\n"; SU->dump(this));
// Move the instruction to its new location in the instruction stream.
MachineInstr *MI = SU->getInstr();
if (&*InsertPos == MI)
++InsertPos;
else {
BB->splice(InsertPos, BB, MI);
Pass->LIS->handleMove(MI);
Andrew Trick
committed
if (Begin == InsertPos)
Begin = MI;
}
// Release dependent instructions for scheduling.
releaseSuccessors(SU);
}
}
bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) {
// Initialize the context of the pass.
MF = &mf;
MLI = &getAnalysis<MachineLoopInfo>();
MDT = &getAnalysis<MachineDominatorTree>();
Lang Hames
committed
LIS = &getAnalysis<LiveIntervals>();
Andrew Trick
committed
TII = MF->getTarget().getInstrInfo();
// Select the scheduler, or set the default.
MachineSchedRegistry::ScheduleDAGCtor Ctor =
MachineSchedRegistry::getDefault();
if (!Ctor) {
Ctor = MachineSchedOpt;
MachineSchedRegistry::setDefault(Ctor);
}
// Instantiate the selected scheduler.
OwningPtr<ScheduleDAGInstrs> Scheduler(Ctor(this));
// Visit all machine basic blocks.
for (MachineFunction::iterator MBB = MF->begin(), MBBEnd = MF->end();
MBB != MBBEnd; ++MBB) {
Andrew Trick
committed
// Break the block into scheduling regions [I, RegionEnd), and schedule each
// region as soon as it is discovered.
unsigned RemainingCount = MBB->size();
for(MachineBasicBlock::iterator RegionEnd = MBB->end();
RegionEnd != MBB->begin();) {
Scheduler->startBlock(MBB);
Andrew Trick
committed
// 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, --RemainingCount) {
Andrew Trick
committed
if (TII->isSchedulingBoundary(llvm::prior(I), MBB, *MF))
break;
}
// Notify the scheduler of the region, even if we may skip scheduling
// it. Perhaps it still needs to be bundled.
Scheduler->enterRegion(MBB, I, RegionEnd, RemainingCount);
// Skip empty scheduling regions (0 or 1 schedulable instructions).
if (I == RegionEnd || I == llvm::prior(RegionEnd)) {
Andrew Trick
committed
RegionEnd = llvm::prior(RegionEnd);
if (I != RegionEnd)
--RemainingCount;
// Close the current region. Bundle the terminator if needed.
Scheduler->exitRegion();
Andrew Trick
committed
continue;
Andrew Trick
committed
DEBUG(dbgs() << "MachineScheduling " << MF->getFunction()->getName()
<< ":BB#" << MBB->getNumber() << "\n From: " << *I << " To: ";
if (RegionEnd != MBB->end()) dbgs() << *RegionEnd;
else dbgs() << "End";
dbgs() << " Remaining: " << RemainingCount << "\n");
Andrew Trick
committed
// Inform ScheduleDAGInstrs of the region being scheduled. It calls back
// to our schedule() method.
Scheduler->schedule();
Scheduler->exitRegion();
// Scheduling has invalidated the current iterator 'I'. Ask the
// scheduler for the top of it's scheduled region.
RegionEnd = Scheduler->begin();
Andrew Trick
committed
}
assert(RemainingCount == 0 && "Instruction count mismatch!");
Scheduler->finishBlock();
void MachineScheduler::print(raw_ostream &O, const Module* m) const {
//===----------------------------------------------------------------------===//
// Placeholder for extending the machine instruction scheduler.
//===----------------------------------------------------------------------===//
namespace {
Andrew Trick
committed
class DefaultMachineScheduler : public ScheduleDAGInstrs {
MachineScheduler *Pass;
public:
DefaultMachineScheduler(MachineScheduler *P):
ScheduleDAGInstrs(*P->MF, *P->MLI, *P->MDT, /*IsPostRA=*/false, P->LIS),
Pass(P) {}
/// schedule - This is called back from ScheduleDAGInstrs::Run() when it's
Andrew Trick
committed
/// time to do some work.
void schedule();
};
} // namespace
static ScheduleDAGInstrs *createDefaultMachineSched(MachineScheduler *P) {
return new DefaultMachineScheduler(P);
}
static MachineSchedRegistry
SchedDefaultRegistry("default", "Activate the scheduler pass, "
"but don't reorder instructions",
createDefaultMachineSched);
/// Schedule - This is called back from ScheduleDAGInstrs::Run() when it's
/// time to do some work.
void DefaultMachineScheduler::schedule() {
buildSchedGraph(&Pass->getAnalysis<AliasAnalysis>());
DEBUG(dbgs() << "********** MI Scheduling **********\n");
DEBUG(for (unsigned su = 0, e = SUnits.size(); su != e; ++su)
SUnits[su].dumpAll(this));
// TODO: Put interesting things here.
Andrew Trick
committed
//
// When this is fully implemented, it will become a subclass of
// ScheduleTopDownLive. So this driver will disappear.
Andrew Trick
committed
//===----------------------------------------------------------------------===//
// Machine Instruction Shuffler for Correctness Testing
//===----------------------------------------------------------------------===//
// Nodes with a higher number have higher priority. This way we attempt to
Andrew Trick
committed
// schedule the latest instructions earliest.
//
// TODO: Relies on the property of the BuildSchedGraph that results in SUnits
// being ordered in sequence top-down.
Andrew Trick
committed
struct ShuffleSUnitOrder {
bool operator()(SUnit *A, SUnit *B) const {
Andrew Trick
committed
}
};
/// Reorder instructions as much as possible.
class InstructionShuffler : public ScheduleTopDownLive {
Andrew Trick
committed
std::priority_queue<SUnit*, std::vector<SUnit*>, ShuffleSUnitOrder> Queue;
InstructionShuffler(MachineScheduler *P):
ScheduleTopDownLive(P) {}
Andrew Trick
committed
/// ScheduleTopDownLive Interface
virtual SUnit *pickNode() {
if (Queue.empty()) return NULL;
SUnit *SU = Queue.top();
Queue.pop();
return SU;
}
virtual void releaseNode(SUnit *SU) {
Queue.push(SU);
static ScheduleDAGInstrs *createInstructionShuffler(MachineScheduler *P) {
return new InstructionShuffler(P);
}
static MachineSchedRegistry ShufflerRegistry("shuffle",
"Shuffle machine instructions",
createInstructionShuffler);
#endif // !NDEBUG