| //===----- SchedulePostRAList.cpp - list scheduler ------------------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This implements a top-down list scheduler, using standard algorithms. | |
| // The basic approach uses a priority queue of available nodes to schedule. | |
| // One at a time, nodes are taken from the priority queue (thus in priority | |
| // order), checked for legality to schedule, and emitted if legal. | |
| // | |
| // Nodes may not be legal to schedule either due to structural hazards (e.g. | |
| // pipeline or resource constraints) or because an input to the instruction has | |
| // not completed execution. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #define DEBUG_TYPE "post-RA-sched" | |
| #include "AntiDepBreaker.h" | |
| #include "AggressiveAntiDepBreaker.h" | |
| #include "CriticalAntiDepBreaker.h" | |
| #include "RegisterClassInfo.h" | |
| #include "ScheduleDAGInstrs.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/CodeGen/LatencyPriorityQueue.h" | |
| #include "llvm/CodeGen/SchedulerRegistry.h" | |
| #include "llvm/CodeGen/MachineDominators.h" | |
| #include "llvm/CodeGen/MachineFrameInfo.h" | |
| #include "llvm/CodeGen/MachineFunctionPass.h" | |
| #include "llvm/CodeGen/MachineLoopInfo.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/ScheduleHazardRecognizer.h" | |
| #include "llvm/Analysis/AliasAnalysis.h" | |
| #include "llvm/Target/TargetLowering.h" | |
| #include "llvm/Target/TargetMachine.h" | |
| #include "llvm/Target/TargetInstrInfo.h" | |
| #include "llvm/Target/TargetRegisterInfo.h" | |
| #include "llvm/Target/TargetSubtargetInfo.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/BitVector.h" | |
| #include "llvm/ADT/Statistic.h" | |
| #include <set> | |
| using namespace llvm; | |
| STATISTIC(NumNoops, "Number of noops inserted"); | |
| STATISTIC(NumStalls, "Number of pipeline stalls"); | |
| STATISTIC(NumFixedAnti, "Number of fixed anti-dependencies"); | |
| // Post-RA scheduling is enabled with | |
| // TargetSubtargetInfo.enablePostRAScheduler(). This flag can be used to | |
| // override the target. | |
| static cl::opt<bool> | |
| EnablePostRAScheduler("post-RA-scheduler", | |
| cl::desc("Enable scheduling after register allocation"), | |
| cl::init(false), cl::Hidden); | |
| static cl::opt<std::string> | |
| EnableAntiDepBreaking("break-anti-dependencies", | |
| cl::desc("Break post-RA scheduling anti-dependencies: " | |
| "\"critical\", \"all\", or \"none\""), | |
| cl::init("none"), cl::Hidden); | |
| // If DebugDiv > 0 then only schedule MBB with (ID % DebugDiv) == DebugMod | |
| static cl::opt<int> | |
| DebugDiv("postra-sched-debugdiv", | |
| cl::desc("Debug control MBBs that are scheduled"), | |
| cl::init(0), cl::Hidden); | |
| static cl::opt<int> | |
| DebugMod("postra-sched-debugmod", | |
| cl::desc("Debug control MBBs that are scheduled"), | |
| cl::init(0), cl::Hidden); | |
| AntiDepBreaker::~AntiDepBreaker() { } | |
| namespace { | |
| class PostRAScheduler : public MachineFunctionPass { | |
| AliasAnalysis *AA; | |
| const TargetInstrInfo *TII; | |
| RegisterClassInfo RegClassInfo; | |
| CodeGenOpt::Level OptLevel; | |
| public: | |
| static char ID; | |
| PostRAScheduler(CodeGenOpt::Level ol) : | |
| MachineFunctionPass(ID), OptLevel(ol) {} | |
| void getAnalysisUsage(AnalysisUsage &AU) const { | |
| AU.setPreservesCFG(); | |
| AU.addRequired<AliasAnalysis>(); | |
| AU.addRequired<MachineDominatorTree>(); | |
| AU.addPreserved<MachineDominatorTree>(); | |
| AU.addRequired<MachineLoopInfo>(); | |
| AU.addPreserved<MachineLoopInfo>(); | |
| MachineFunctionPass::getAnalysisUsage(AU); | |
| } | |
| const char *getPassName() const { | |
| return "Post RA top-down list latency scheduler"; | |
| } | |
| bool runOnMachineFunction(MachineFunction &Fn); | |
| }; | |
| char PostRAScheduler::ID = 0; | |
| class SchedulePostRATDList : public ScheduleDAGInstrs { | |
| /// AvailableQueue - The priority queue to use for the available SUnits. | |
| /// | |
| LatencyPriorityQueue AvailableQueue; | |
| /// PendingQueue - This contains all of the instructions whose operands have | |
| /// been issued, but their results are not ready yet (due to the latency of | |
| /// the operation). Once the operands becomes available, the instruction is | |
| /// added to the AvailableQueue. | |
| std::vector<SUnit*> PendingQueue; | |
| /// Topo - A topological ordering for SUnits. | |
| ScheduleDAGTopologicalSort Topo; | |
| /// HazardRec - The hazard recognizer to use. | |
| ScheduleHazardRecognizer *HazardRec; | |
| /// AntiDepBreak - Anti-dependence breaking object, or NULL if none | |
| AntiDepBreaker *AntiDepBreak; | |
| /// AA - AliasAnalysis for making memory reference queries. | |
| AliasAnalysis *AA; | |
| /// KillIndices - The index of the most recent kill (proceding bottom-up), | |
| /// or ~0u if the register is not live. | |
| std::vector<unsigned> KillIndices; | |
| public: | |
| SchedulePostRATDList( | |
| MachineFunction &MF, MachineLoopInfo &MLI, MachineDominatorTree &MDT, | |
| AliasAnalysis *AA, const RegisterClassInfo&, | |
| TargetSubtargetInfo::AntiDepBreakMode AntiDepMode, | |
| SmallVectorImpl<TargetRegisterClass*> &CriticalPathRCs); | |
| ~SchedulePostRATDList(); | |
| /// StartBlock - Initialize register live-range state for scheduling in | |
| /// this block. | |
| /// | |
| void StartBlock(MachineBasicBlock *BB); | |
| /// Schedule - Schedule the instruction range using list scheduling. | |
| /// | |
| void Schedule(); | |
| /// Observe - Update liveness information to account for the current | |
| /// instruction, which will not be scheduled. | |
| /// | |
| void Observe(MachineInstr *MI, unsigned Count); | |
| /// FinishBlock - Clean up register live-range state. | |
| /// | |
| void FinishBlock(); | |
| /// FixupKills - Fix register kill flags that have been made | |
| /// invalid due to scheduling | |
| /// | |
| void FixupKills(MachineBasicBlock *MBB); | |
| private: | |
| void ReleaseSucc(SUnit *SU, SDep *SuccEdge); | |
| void ReleaseSuccessors(SUnit *SU); | |
| void ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle); | |
| void ListScheduleTopDown(); | |
| void StartBlockForKills(MachineBasicBlock *BB); | |
| // ToggleKillFlag - Toggle a register operand kill flag. Other | |
| // adjustments may be made to the instruction if necessary. Return | |
| // true if the operand has been deleted, false if not. | |
| bool ToggleKillFlag(MachineInstr *MI, MachineOperand &MO); | |
| }; | |
| } | |
| SchedulePostRATDList::SchedulePostRATDList( | |
| MachineFunction &MF, MachineLoopInfo &MLI, MachineDominatorTree &MDT, | |
| AliasAnalysis *AA, const RegisterClassInfo &RCI, | |
| TargetSubtargetInfo::AntiDepBreakMode AntiDepMode, | |
| SmallVectorImpl<TargetRegisterClass*> &CriticalPathRCs) | |
| : ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits), AA(AA), | |
| KillIndices(TRI->getNumRegs()) | |
| { | |
| const TargetMachine &TM = MF.getTarget(); | |
| const InstrItineraryData *InstrItins = TM.getInstrItineraryData(); | |
| HazardRec = | |
| TM.getInstrInfo()->CreateTargetPostRAHazardRecognizer(InstrItins, this); | |
| AntiDepBreak = | |
| ((AntiDepMode == TargetSubtargetInfo::ANTIDEP_ALL) ? | |
| (AntiDepBreaker *)new AggressiveAntiDepBreaker(MF, RCI, CriticalPathRCs) : | |
| ((AntiDepMode == TargetSubtargetInfo::ANTIDEP_CRITICAL) ? | |
| (AntiDepBreaker *)new CriticalAntiDepBreaker(MF, RCI) : NULL)); | |
| } | |
| SchedulePostRATDList::~SchedulePostRATDList() { | |
| delete HazardRec; | |
| delete AntiDepBreak; | |
| } | |
| bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { | |
| TII = Fn.getTarget().getInstrInfo(); | |
| MachineLoopInfo &MLI = getAnalysis<MachineLoopInfo>(); | |
| MachineDominatorTree &MDT = getAnalysis<MachineDominatorTree>(); | |
| AliasAnalysis *AA = &getAnalysis<AliasAnalysis>(); | |
| RegClassInfo.runOnMachineFunction(Fn); | |
| // Check for explicit enable/disable of post-ra scheduling. | |
| TargetSubtargetInfo::AntiDepBreakMode AntiDepMode = TargetSubtargetInfo::ANTIDEP_NONE; | |
| SmallVector<TargetRegisterClass*, 4> CriticalPathRCs; | |
| if (EnablePostRAScheduler.getPosition() > 0) { | |
| if (!EnablePostRAScheduler) | |
| return false; | |
| } else { | |
| // Check that post-RA scheduling is enabled for this target. | |
| // This may upgrade the AntiDepMode. | |
| const TargetSubtargetInfo &ST = Fn.getTarget().getSubtarget<TargetSubtargetInfo>(); | |
| if (!ST.enablePostRAScheduler(OptLevel, AntiDepMode, CriticalPathRCs)) | |
| return false; | |
| } | |
| // Check for antidep breaking override... | |
| if (EnableAntiDepBreaking.getPosition() > 0) { | |
| AntiDepMode = (EnableAntiDepBreaking == "all") | |
| ? TargetSubtargetInfo::ANTIDEP_ALL | |
| : ((EnableAntiDepBreaking == "critical") | |
| ? TargetSubtargetInfo::ANTIDEP_CRITICAL | |
| : TargetSubtargetInfo::ANTIDEP_NONE); | |
| } | |
| DEBUG(dbgs() << "PostRAScheduler\n"); | |
| SchedulePostRATDList Scheduler(Fn, MLI, MDT, AA, RegClassInfo, AntiDepMode, | |
| CriticalPathRCs); | |
| // Loop over all of the basic blocks | |
| for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); | |
| MBB != MBBe; ++MBB) { | |
| #ifndef NDEBUG | |
| // If DebugDiv > 0 then only schedule MBB with (ID % DebugDiv) == DebugMod | |
| if (DebugDiv > 0) { | |
| static int bbcnt = 0; | |
| if (bbcnt++ % DebugDiv != DebugMod) | |
| continue; | |
| dbgs() << "*** DEBUG scheduling " << Fn.getFunction()->getNameStr() << | |
| ":BB#" << MBB->getNumber() << " ***\n"; | |
| } | |
| #endif | |
| // Initialize register live-range state for scheduling in this block. | |
| Scheduler.StartBlock(MBB); | |
| // Schedule each sequence of instructions not interrupted by a label | |
| // or anything else that effectively needs to shut down scheduling. | |
| MachineBasicBlock::iterator Current = MBB->end(); | |
| unsigned Count = MBB->size(), CurrentCount = Count; | |
| for (MachineBasicBlock::iterator I = Current; I != MBB->begin(); ) { | |
| MachineInstr *MI = llvm::prior(I); | |
| if (TII->isSchedulingBoundary(MI, MBB, Fn)) { | |
| Scheduler.Run(MBB, I, Current, CurrentCount); | |
| Scheduler.EmitSchedule(); | |
| Current = MI; | |
| CurrentCount = Count - 1; | |
| Scheduler.Observe(MI, CurrentCount); | |
| } | |
| I = MI; | |
| --Count; | |
| } | |
| assert(Count == 0 && "Instruction count mismatch!"); | |
| assert((MBB->begin() == Current || CurrentCount != 0) && | |
| "Instruction count mismatch!"); | |
| Scheduler.Run(MBB, MBB->begin(), Current, CurrentCount); | |
| Scheduler.EmitSchedule(); | |
| // Clean up register live-range state. | |
| Scheduler.FinishBlock(); | |
| // Update register kills | |
| Scheduler.FixupKills(MBB); | |
| } | |
| return true; | |
| } | |
| /// StartBlock - Initialize register live-range state for scheduling in | |
| /// this block. | |
| /// | |
| void SchedulePostRATDList::StartBlock(MachineBasicBlock *BB) { | |
| // Call the superclass. | |
| ScheduleDAGInstrs::StartBlock(BB); | |
| // Reset the hazard recognizer and anti-dep breaker. | |
| HazardRec->Reset(); | |
| if (AntiDepBreak != NULL) | |
| AntiDepBreak->StartBlock(BB); | |
| } | |
| /// Schedule - Schedule the instruction range using list scheduling. | |
| /// | |
| void SchedulePostRATDList::Schedule() { | |
| // Build the scheduling graph. | |
| BuildSchedGraph(AA); | |
| if (AntiDepBreak != NULL) { | |
| unsigned Broken = | |
| AntiDepBreak->BreakAntiDependencies(SUnits, Begin, InsertPos, | |
| InsertPosIndex, DbgValues); | |
| if (Broken != 0) { | |
| // We made changes. Update the dependency graph. | |
| // Theoretically we could update the graph in place: | |
| // When a live range is changed to use a different register, remove | |
| // the def's anti-dependence *and* output-dependence edges due to | |
| // that register, and add new anti-dependence and output-dependence | |
| // edges based on the next live range of the register. | |
| SUnits.clear(); | |
| Sequence.clear(); | |
| EntrySU = SUnit(); | |
| ExitSU = SUnit(); | |
| BuildSchedGraph(AA); | |
| NumFixedAnti += Broken; | |
| } | |
| } | |
| DEBUG(dbgs() << "********** List Scheduling **********\n"); | |
| DEBUG(for (unsigned su = 0, e = SUnits.size(); su != e; ++su) | |
| SUnits[su].dumpAll(this)); | |
| AvailableQueue.initNodes(SUnits); | |
| ListScheduleTopDown(); | |
| AvailableQueue.releaseState(); | |
| } | |
| /// Observe - Update liveness information to account for the current | |
| /// instruction, which will not be scheduled. | |
| /// | |
| void SchedulePostRATDList::Observe(MachineInstr *MI, unsigned Count) { | |
| if (AntiDepBreak != NULL) | |
| AntiDepBreak->Observe(MI, Count, InsertPosIndex); | |
| } | |
| /// FinishBlock - Clean up register live-range state. | |
| /// | |
| void SchedulePostRATDList::FinishBlock() { | |
| if (AntiDepBreak != NULL) | |
| AntiDepBreak->FinishBlock(); | |
| // Call the superclass. | |
| ScheduleDAGInstrs::FinishBlock(); | |
| } | |
| /// StartBlockForKills - Initialize register live-range state for updating kills | |
| /// | |
| void SchedulePostRATDList::StartBlockForKills(MachineBasicBlock *BB) { | |
| // Initialize the indices to indicate that no registers are live. | |
| for (unsigned i = 0; i < TRI->getNumRegs(); ++i) | |
| KillIndices[i] = ~0u; | |
| // Determine the live-out physregs for this block. | |
| if (!BB->empty() && BB->back().getDesc().isReturn()) { | |
| // In a return block, examine the function live-out regs. | |
| for (MachineRegisterInfo::liveout_iterator I = MRI.liveout_begin(), | |
| E = MRI.liveout_end(); I != E; ++I) { | |
| unsigned Reg = *I; | |
| KillIndices[Reg] = BB->size(); | |
| // Repeat, for all subregs. | |
| for (const unsigned *Subreg = TRI->getSubRegisters(Reg); | |
| *Subreg; ++Subreg) { | |
| KillIndices[*Subreg] = BB->size(); | |
| } | |
| } | |
| } | |
| else { | |
| // In a non-return block, examine the live-in regs of all successors. | |
| for (MachineBasicBlock::succ_iterator SI = BB->succ_begin(), | |
| SE = BB->succ_end(); SI != SE; ++SI) { | |
| for (MachineBasicBlock::livein_iterator I = (*SI)->livein_begin(), | |
| E = (*SI)->livein_end(); I != E; ++I) { | |
| unsigned Reg = *I; | |
| KillIndices[Reg] = BB->size(); | |
| // Repeat, for all subregs. | |
| for (const unsigned *Subreg = TRI->getSubRegisters(Reg); | |
| *Subreg; ++Subreg) { | |
| KillIndices[*Subreg] = BB->size(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| bool SchedulePostRATDList::ToggleKillFlag(MachineInstr *MI, | |
| MachineOperand &MO) { | |
| // Setting kill flag... | |
| if (!MO.isKill()) { | |
| MO.setIsKill(true); | |
| return false; | |
| } | |
| // If MO itself is live, clear the kill flag... | |
| if (KillIndices[MO.getReg()] != ~0u) { | |
| MO.setIsKill(false); | |
| return false; | |
| } | |
| // If any subreg of MO is live, then create an imp-def for that | |
| // subreg and keep MO marked as killed. | |
| MO.setIsKill(false); | |
| bool AllDead = true; | |
| const unsigned SuperReg = MO.getReg(); | |
| for (const unsigned *Subreg = TRI->getSubRegisters(SuperReg); | |
| *Subreg; ++Subreg) { | |
| if (KillIndices[*Subreg] != ~0u) { | |
| MI->addOperand(MachineOperand::CreateReg(*Subreg, | |
| true /*IsDef*/, | |
| true /*IsImp*/, | |
| false /*IsKill*/, | |
| false /*IsDead*/)); | |
| AllDead = false; | |
| } | |
| } | |
| if(AllDead) | |
| MO.setIsKill(true); | |
| return false; | |
| } | |
| /// FixupKills - Fix the register kill flags, they may have been made | |
| /// incorrect by instruction reordering. | |
| /// | |
| void SchedulePostRATDList::FixupKills(MachineBasicBlock *MBB) { | |
| DEBUG(dbgs() << "Fixup kills for BB#" << MBB->getNumber() << '\n'); | |
| std::set<unsigned> killedRegs; | |
| BitVector ReservedRegs = TRI->getReservedRegs(MF); | |
| StartBlockForKills(MBB); | |
| // Examine block from end to start... | |
| unsigned Count = MBB->size(); | |
| for (MachineBasicBlock::iterator I = MBB->end(), E = MBB->begin(); | |
| I != E; --Count) { | |
| MachineInstr *MI = --I; | |
| if (MI->isDebugValue()) | |
| continue; | |
| // Update liveness. Registers that are defed but not used in this | |
| // instruction are now dead. Mark register and all subregs as they | |
| // are completely defined. | |
| for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { | |
| MachineOperand &MO = MI->getOperand(i); | |
| if (!MO.isReg()) continue; | |
| unsigned Reg = MO.getReg(); | |
| if (Reg == 0) continue; | |
| if (!MO.isDef()) continue; | |
| // Ignore two-addr defs. | |
| if (MI->isRegTiedToUseOperand(i)) continue; | |
| KillIndices[Reg] = ~0u; | |
| // Repeat for all subregs. | |
| for (const unsigned *Subreg = TRI->getSubRegisters(Reg); | |
| *Subreg; ++Subreg) { | |
| KillIndices[*Subreg] = ~0u; | |
| } | |
| } | |
| // Examine all used registers and set/clear kill flag. When a | |
| // register is used multiple times we only set the kill flag on | |
| // the first use. | |
| killedRegs.clear(); | |
| for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { | |
| MachineOperand &MO = MI->getOperand(i); | |
| if (!MO.isReg() || !MO.isUse()) continue; | |
| unsigned Reg = MO.getReg(); | |
| if ((Reg == 0) || ReservedRegs.test(Reg)) continue; | |
| bool kill = false; | |
| if (killedRegs.find(Reg) == killedRegs.end()) { | |
| kill = true; | |
| // A register is not killed if any subregs are live... | |
| for (const unsigned *Subreg = TRI->getSubRegisters(Reg); | |
| *Subreg; ++Subreg) { | |
| if (KillIndices[*Subreg] != ~0u) { | |
| kill = false; | |
| break; | |
| } | |
| } | |
| // If subreg is not live, then register is killed if it became | |
| // live in this instruction | |
| if (kill) | |
| kill = (KillIndices[Reg] == ~0u); | |
| } | |
| if (MO.isKill() != kill) { | |
| DEBUG(dbgs() << "Fixing " << MO << " in "); | |
| // Warning: ToggleKillFlag may invalidate MO. | |
| ToggleKillFlag(MI, MO); | |
| DEBUG(MI->dump()); | |
| } | |
| killedRegs.insert(Reg); | |
| } | |
| // Mark any used register (that is not using undef) and subregs as | |
| // now live... | |
| for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { | |
| MachineOperand &MO = MI->getOperand(i); | |
| if (!MO.isReg() || !MO.isUse() || MO.isUndef()) continue; | |
| unsigned Reg = MO.getReg(); | |
| if ((Reg == 0) || ReservedRegs.test(Reg)) continue; | |
| KillIndices[Reg] = Count; | |
| for (const unsigned *Subreg = TRI->getSubRegisters(Reg); | |
| *Subreg; ++Subreg) { | |
| KillIndices[*Subreg] = Count; | |
| } | |
| } | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Top-Down Scheduling | |
| //===----------------------------------------------------------------------===// | |
| /// ReleaseSucc - Decrement the NumPredsLeft count of a successor. Add it to | |
| /// the PendingQueue if the count reaches zero. Also update its cycle bound. | |
| void SchedulePostRATDList::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; | |
| // Standard scheduler algorithms will recompute the depth of the successor | |
| // here as such: | |
| // SuccSU->setDepthToAtLeast(SU->getDepth() + SuccEdge->getLatency()); | |
| // | |
| // However, we lazily compute node depth instead. Note that | |
| // ScheduleNodeTopDown has already updated the depth of this node which causes | |
| // all descendents to be marked dirty. Setting the successor depth explicitly | |
| // here would cause depth to be recomputed for all its ancestors. If the | |
| // successor is not yet ready (because of a transitively redundant edge) then | |
| // this causes depth computation to be quadratic in the size of the DAG. | |
| // If all the node's predecessors are scheduled, this node is ready | |
| // to be scheduled. Ignore the special ExitSU node. | |
| if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU) | |
| PendingQueue.push_back(SuccSU); | |
| } | |
| /// ReleaseSuccessors - Call ReleaseSucc on each of SU's successors. | |
| void SchedulePostRATDList::ReleaseSuccessors(SUnit *SU) { | |
| for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); | |
| I != E; ++I) { | |
| ReleaseSucc(SU, &*I); | |
| } | |
| } | |
| /// ScheduleNodeTopDown - Add the node to the schedule. Decrement the pending | |
| /// count of its successors. If a successor pending count is zero, add it to | |
| /// the Available queue. | |
| void SchedulePostRATDList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) { | |
| DEBUG(dbgs() << "*** Scheduling [" << CurCycle << "]: "); | |
| DEBUG(SU->dump(this)); | |
| Sequence.push_back(SU); | |
| assert(CurCycle >= SU->getDepth() && | |
| "Node scheduled above its depth!"); | |
| SU->setDepthToAtLeast(CurCycle); | |
| ReleaseSuccessors(SU); | |
| SU->isScheduled = true; | |
| AvailableQueue.ScheduledNode(SU); | |
| } | |
| /// ListScheduleTopDown - The main loop of list scheduling for top-down | |
| /// schedulers. | |
| void SchedulePostRATDList::ListScheduleTopDown() { | |
| unsigned CurCycle = 0; | |
| // We're scheduling top-down but we're visiting the regions in | |
| // bottom-up order, so we don't know the hazards at the start of a | |
| // region. So assume no hazards (this should usually be ok as most | |
| // blocks are a single region). | |
| HazardRec->Reset(); | |
| // Release any successors of the special Entry node. | |
| ReleaseSuccessors(&EntrySU); | |
| // Add all leaves to Available queue. | |
| for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { | |
| // It is available if it has no predecessors. | |
| bool available = SUnits[i].Preds.empty(); | |
| if (available) { | |
| AvailableQueue.push(&SUnits[i]); | |
| SUnits[i].isAvailable = true; | |
| } | |
| } | |
| // In any cycle where we can't schedule any instructions, we must | |
| // stall or emit a noop, depending on the target. | |
| bool CycleHasInsts = false; | |
| // While Available queue is not empty, grab the node with the highest | |
| // priority. If it is not ready put it back. Schedule the node. | |
| std::vector<SUnit*> NotReady; | |
| Sequence.reserve(SUnits.size()); | |
| while (!AvailableQueue.empty() || !PendingQueue.empty()) { | |
| // Check to see if any of the pending instructions are ready to issue. If | |
| // so, add them to the available queue. | |
| unsigned MinDepth = ~0u; | |
| for (unsigned i = 0, e = PendingQueue.size(); i != e; ++i) { | |
| if (PendingQueue[i]->getDepth() <= CurCycle) { | |
| AvailableQueue.push(PendingQueue[i]); | |
| PendingQueue[i]->isAvailable = true; | |
| PendingQueue[i] = PendingQueue.back(); | |
| PendingQueue.pop_back(); | |
| --i; --e; | |
| } else if (PendingQueue[i]->getDepth() < MinDepth) | |
| MinDepth = PendingQueue[i]->getDepth(); | |
| } | |
| DEBUG(dbgs() << "\n*** Examining Available\n"; AvailableQueue.dump(this)); | |
| SUnit *FoundSUnit = 0; | |
| bool HasNoopHazards = false; | |
| while (!AvailableQueue.empty()) { | |
| SUnit *CurSUnit = AvailableQueue.pop(); | |
| ScheduleHazardRecognizer::HazardType HT = | |
| HazardRec->getHazardType(CurSUnit, 0/*no stalls*/); | |
| if (HT == ScheduleHazardRecognizer::NoHazard) { | |
| FoundSUnit = CurSUnit; | |
| break; | |
| } | |
| // Remember if this is a noop hazard. | |
| HasNoopHazards |= HT == ScheduleHazardRecognizer::NoopHazard; | |
| NotReady.push_back(CurSUnit); | |
| } | |
| // Add the nodes that aren't ready back onto the available list. | |
| if (!NotReady.empty()) { | |
| AvailableQueue.push_all(NotReady); | |
| NotReady.clear(); | |
| } | |
| // If we found a node to schedule... | |
| if (FoundSUnit) { | |
| // ... schedule the node... | |
| ScheduleNodeTopDown(FoundSUnit, CurCycle); | |
| HazardRec->EmitInstruction(FoundSUnit); | |
| CycleHasInsts = true; | |
| if (HazardRec->atIssueLimit()) { | |
| DEBUG(dbgs() << "*** Max instructions per cycle " << CurCycle << '\n'); | |
| HazardRec->AdvanceCycle(); | |
| ++CurCycle; | |
| CycleHasInsts = false; | |
| } | |
| } else { | |
| if (CycleHasInsts) { | |
| DEBUG(dbgs() << "*** Finished cycle " << CurCycle << '\n'); | |
| HazardRec->AdvanceCycle(); | |
| } else if (!HasNoopHazards) { | |
| // Otherwise, we have a pipeline stall, but no other problem, | |
| // just advance the current cycle and try again. | |
| DEBUG(dbgs() << "*** Stall in cycle " << CurCycle << '\n'); | |
| HazardRec->AdvanceCycle(); | |
| ++NumStalls; | |
| } else { | |
| // Otherwise, we have no instructions to issue and we have instructions | |
| // that will fault if we don't do this right. This is the case for | |
| // processors without pipeline interlocks and other cases. | |
| DEBUG(dbgs() << "*** Emitting noop in cycle " << CurCycle << '\n'); | |
| HazardRec->EmitNoop(); | |
| Sequence.push_back(0); // NULL here means noop | |
| ++NumNoops; | |
| } | |
| ++CurCycle; | |
| CycleHasInsts = false; | |
| } | |
| } | |
| #ifndef NDEBUG | |
| VerifySchedule(/*isBottomUp=*/false); | |
| #endif | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Public Constructor Functions | |
| //===----------------------------------------------------------------------===// | |
| FunctionPass *llvm::createPostRAScheduler(CodeGenOpt::Level OptLevel) { | |
| return new PostRAScheduler(OptLevel); | |
| } |