Index: include/llvm/CodeGen/MachineScheduler.h =================================================================== --- include/llvm/CodeGen/MachineScheduler.h +++ include/llvm/CodeGen/MachineScheduler.h @@ -332,9 +332,19 @@ void viewGraph(const Twine &Name, const Twine &Title) override; void viewGraph() override; + // Dumps additional debug information for the given SUnit Only called within + // DEBUG(). + virtual void dumpDebugInfoForSU(const SUnit &SU) const {} + protected: // Top-Level entry points for the schedule() driver... + // Build the scheduling DAG. + virtual void buildDAG() { buildSchedGraph(AA); }; + + /// Move an instruction and update state. + virtual void scheduleMI(SUnit *SU, bool IsTopNode); + /// Apply each ScheduleDAGMutation step in order. This allows different /// instances of ScheduleDAGMI to perform custom DAG postprocessing. void postprocessDAG(); @@ -441,6 +451,10 @@ return SUPressureDiffs[SU->NodeNum]; } + const PressureDiff &getPressureDiff(const SUnit *SU) const { + return SUPressureDiffs[SU->NodeNum]; + } + /// Compute a DFSResult after DAG building is complete, and before any /// queue comparisons. void computeDFSResult(); @@ -458,10 +472,6 @@ MachineBasicBlock::iterator end, unsigned regioninstrs) override; - /// Implement ScheduleDAGInstrs interface for scheduling a sequence of - /// reorderable instructions. - void schedule() override; - /// Compute the cyclic critical path through the DAG. unsigned computeCyclicCriticalPath(); @@ -472,14 +482,14 @@ /// enabled. This sets up three trackers. RPTracker will cover the entire DAG /// region, TopTracker and BottomTracker will be initialized to the top and /// bottom of the DAG region without covereing any unscheduled instruction. - void buildDAGWithRegPressure(); + void buildDAG() override; /// Release ExitSU predecessors and setup scheduler queues. Re-position /// the Top RP tracker in case the region beginning has changed. void initQueues(ArrayRef TopRoots, ArrayRef BotRoots); /// Move an instruction and update register pressure. - void scheduleMI(SUnit *SU, bool IsTopNode); + void scheduleMI(SUnit *SU, bool IsTopNode) override; // Lesser helpers... @@ -491,6 +501,8 @@ const std::vector &NewMaxPressure); void collectVRegUses(SUnit &SU); + + void dumpDebugInfoForSU(const SUnit &SU) const override; }; //===----------------------------------------------------------------------===// Index: lib/CodeGen/MachineScheduler.cpp =================================================================== --- lib/CodeGen/MachineScheduler.cpp +++ lib/CodeGen/MachineScheduler.cpp @@ -699,16 +699,43 @@ return true; } +void ScheduleDAGMI::scheduleMI(SUnit *SU, bool IsTopNode) { + MachineInstr *MI = SU->getInstr(); + if (IsTopNode) { + assert(SU->isTopReady() && "node still has unscheduled dependencies"); + if (&*CurrentTop == MI) + CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom); + else + moveInstruction(MI, CurrentTop); + } else { + assert(SU->isBottomReady() && "node still has unscheduled dependencies"); + MachineBasicBlock::iterator priorII = + priorNonDebug(CurrentBottom, CurrentTop); + if (&*priorII == MI) + CurrentBottom = priorII; + else { + if (&*CurrentTop == MI) + CurrentTop = nextIfDebug(++CurrentTop, priorII); + moveInstruction(MI, CurrentBottom); + CurrentBottom = MI; + } + } +} + /// Per-region scheduling driver, called back from -/// MachineScheduler::runOnMachineFunction. This is a simplified driver that -/// does not consider liveness or register pressure. It is useful for PostRA -/// scheduling and potentially other custom schedulers. +/// MachineScheduler::runOnMachineFunction +/// This is a skeletal driver, with all the functionality pushed into helpers, +/// so that it can be easily extended by experimental schedulers. Generally, +/// implementing MachineSchedStrategy should be sufficient to implement a new +/// scheduling algorithm. However, if a scheduler further subclasses +/// ScheduleDAGMI then it will want to override this virtual method in order +/// to update any specialized state. void ScheduleDAGMI::schedule() { DEBUG(dbgs() << "ScheduleDAGMI::schedule starting\n"); DEBUG(SchedImpl->dumpPolicy()); // Build the DAG. - buildSchedGraph(AA); + buildDAG(); Topo.InitDAGTopologicalSorting(); @@ -724,8 +751,11 @@ DEBUG( if (EntrySU.getInstr() != nullptr) EntrySU.dumpAll(this); - for (unsigned su = 0, e = SUnits.size(); su != e; ++su) - SUnits[su].dumpAll(this); + for (const SUnit &SU : SUnits) { + SU.dumpAll(this); + dumpDebugInfoForSU(SU); + } + dbgs() << '\n'; if (ExitSU.getInstr() != nullptr) ExitSU.dumpAll(this); ); @@ -744,26 +774,8 @@ if (!checkSchedLimit()) break; - MachineInstr *MI = SU->getInstr(); - if (IsTopNode) { - assert(SU->isTopReady() && "node still has unscheduled dependencies"); - if (&*CurrentTop == MI) - CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom); - else - moveInstruction(MI, CurrentTop); - } else { - assert(SU->isBottomReady() && "node still has unscheduled dependencies"); - MachineBasicBlock::iterator priorII = - priorNonDebug(CurrentBottom, CurrentTop); - if (&*priorII == MI) - CurrentBottom = priorII; - else { - if (&*CurrentTop == MI) - CurrentTop = nextIfDebug(++CurrentTop, priorII); - moveInstruction(MI, CurrentBottom); - CurrentBottom = MI; - } - } + scheduleMI(SU, IsTopNode); + // Notify the scheduling strategy before updating the DAG. // This sets the scheduled node's ReadyCycle to CurrCycle. When updateQueues // runs, it can then use the accurate ReadyCycle time to determine whether @@ -1138,97 +1150,8 @@ } } -/// schedule - Called back from MachineScheduler::runOnMachineFunction -/// after setting up the current scheduling region. [RegionBegin, RegionEnd) -/// only includes instructions that have DAG nodes, not scheduling boundaries. -/// -/// This is a skeletal driver, with all the functionality pushed into helpers, -/// so that it can be easily extended by experimental schedulers. Generally, -/// implementing MachineSchedStrategy should be sufficient to implement a new -/// scheduling algorithm. However, if a scheduler further subclasses -/// ScheduleDAGMILive then it will want to override this virtual method in order -/// to update any specialized state. -void ScheduleDAGMILive::schedule() { - DEBUG(dbgs() << "ScheduleDAGMILive::schedule starting\n"); - DEBUG(SchedImpl->dumpPolicy()); - buildDAGWithRegPressure(); - - Topo.InitDAGTopologicalSorting(); - - postprocessDAG(); - - SmallVector TopRoots, BotRoots; - findRootsAndBiasEdges(TopRoots, BotRoots); - - // Initialize the strategy before modifying the DAG. - // This may initialize a DFSResult to be used for queue priority. - SchedImpl->initialize(this); - - DEBUG( - if (EntrySU.getInstr() != nullptr) - EntrySU.dumpAll(this); - for (const SUnit &SU : SUnits) { - SU.dumpAll(this); - if (ShouldTrackPressure) { - dbgs() << " Pressure Diff : "; - getPressureDiff(&SU).dump(*TRI); - } - dbgs() << " Single Issue : "; - if (SchedModel.mustBeginGroup(SU.getInstr()) && - SchedModel.mustEndGroup(SU.getInstr())) - dbgs() << "true;"; - else - dbgs() << "false;"; - dbgs() << '\n'; - } - if (ExitSU.getInstr() != nullptr) - ExitSU.dumpAll(this); - ); - if (ViewMISchedDAGs) viewGraph(); - - // Initialize ready queues now that the DAG and priority data are finalized. - initQueues(TopRoots, BotRoots); - - bool IsTopNode = false; - while (true) { - DEBUG(dbgs() << "** ScheduleDAGMILive::schedule picking next node\n"); - SUnit *SU = SchedImpl->pickNode(IsTopNode); - if (!SU) break; - - assert(!SU->isScheduled && "Node already scheduled"); - if (!checkSchedLimit()) - break; - - scheduleMI(SU, IsTopNode); - - if (DFSResult) { - unsigned SubtreeID = DFSResult->getSubtreeID(SU); - if (!ScheduledTrees.test(SubtreeID)) { - ScheduledTrees.set(SubtreeID); - DFSResult->scheduleTree(SubtreeID); - SchedImpl->scheduleTree(SubtreeID); - } - } - - // Notify the scheduling strategy after updating the DAG. - SchedImpl->schedNode(SU, IsTopNode); - - updateQueues(SU, IsTopNode); - } - assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); - - placeDebugValues(); - - DEBUG({ - unsigned BBNum = begin()->getParent()->getNumber(); - dbgs() << "*** Final schedule for BB#" << BBNum << " ***\n"; - dumpSchedule(); - dbgs() << '\n'; - }); -} - /// Build the DAG and setup three register pressure trackers. -void ScheduleDAGMILive::buildDAGWithRegPressure() { +void ScheduleDAGMILive::buildDAG() { if (!ShouldTrackPressure) { RPTracker.reset(); RegionCriticalPSets.clear(); @@ -1251,6 +1174,21 @@ initRegPressure(); } +void ScheduleDAGMILive::dumpDebugInfoForSU(const SUnit &SU) const { + DEBUG( + if (ShouldTrackPressure) { + dbgs() << " Pressure Diff : "; + getPressureDiff(&SU).dump(*TRI); + } + dbgs() << " Single Issue : "; + if (SchedModel.mustBeginGroup(SU.getInstr()) && + SchedModel.mustEndGroup(SU.getInstr())) + dbgs() << "true;"; + else + dbgs() << "false;"; + ); +} + void ScheduleDAGMILive::computeDFSResult() { if (!DFSResult) DFSResult = new SchedDFSResult(/*BottomU*/true, MinSubtreeSize); @@ -1432,6 +1370,15 @@ updatePressureDiffs(LiveUses); } } + + if (DFSResult) { + unsigned SubtreeID = DFSResult->getSubtreeID(SU); + if (!ScheduledTrees.test(SubtreeID)) { + ScheduledTrees.set(SubtreeID); + DFSResult->scheduleTree(SubtreeID); + SchedImpl->scheduleTree(SubtreeID); + } + } } //===----------------------------------------------------------------------===// Index: lib/Target/AMDGPU/SIMachineScheduler.cpp =================================================================== --- lib/Target/AMDGPU/SIMachineScheduler.cpp +++ lib/Target/AMDGPU/SIMachineScheduler.cpp @@ -1878,7 +1878,7 @@ SIScheduleBlockResult Best, Temp; DEBUG(dbgs() << "Preparing Scheduling\n"); - buildDAGWithRegPressure(); + buildDAG(); DEBUG( for(SUnit& SU : SUnits) SU.dumpAll(this) Index: lib/Target/Hexagon/HexagonMachineScheduler.cpp =================================================================== --- lib/Target/Hexagon/HexagonMachineScheduler.cpp +++ lib/Target/Hexagon/HexagonMachineScheduler.cpp @@ -261,7 +261,7 @@ << " at loop depth " << MLI->getLoopDepth(BB) << " \n"); - buildDAGWithRegPressure(); + buildDAG(); SmallVector TopRoots, BotRoots; findRootsAndBiasEdges(TopRoots, BotRoots); Index: test/CodeGen/AMDGPU/schedule-regpressure.mir =================================================================== --- test/CodeGen/AMDGPU/schedule-regpressure.mir +++ test/CodeGen/AMDGPU/schedule-regpressure.mir @@ -3,7 +3,7 @@ # Check there is no SReg_32 pressure created by DS_* instructions because of M0 use -# CHECK: ScheduleDAGMILive::schedule starting +# CHECK: ScheduleDAGMI::schedule starting # CHECK: SU({{.*}} = DS_READ_B32 {{.*}} %M0, %EXEC # CHECK: Pressure Diff : {{$}} # CHECK: SU({{.*}} DS_WRITE_B32 Index: test/CodeGen/ARM/misched-int-basic-thumb2.mir =================================================================== --- test/CodeGen/ARM/misched-int-basic-thumb2.mir +++ test/CodeGen/ARM/misched-int-basic-thumb2.mir @@ -96,7 +96,7 @@ # CHECK_A9: Latency : 3 # CHECK_SWIFT: Latency : 7 # CHECK_R52: Latency : 4 -# CHECK: ** ScheduleDAGMILive::schedule picking next node +# CHECK: ** ScheduleDAGMI::schedule picking next node ... --- name: foo Index: test/CodeGen/ARM/misched-int-basic.mir =================================================================== --- test/CodeGen/ARM/misched-int-basic.mir +++ test/CodeGen/ARM/misched-int-basic.mir @@ -62,7 +62,7 @@ # CHECK_SWIFT: Latency : 7 # CHECK_A9: Latency : 3 # CHECK_R52: Latency : 4 -# CHECK: ** ScheduleDAGMILive::schedule picking next node +# CHECK: ** ScheduleDAGMI::schedule picking next node ... --- name: foo Index: test/CodeGen/ARM/single-issue-r52.mir =================================================================== --- test/CodeGen/ARM/single-issue-r52.mir +++ test/CodeGen/ARM/single-issue-r52.mir @@ -19,7 +19,7 @@ declare %struct.__neon_int8x8x4_t @llvm.arm.neon.vld4.v8i8.p0i8(i8*, i32) # CHECK: ********** MI Scheduling ********** -# CHECK: ScheduleDAGMILive::schedule starting +# CHECK: ScheduleDAGMI::schedule starting # CHECK: SU(1): %vreg1 = VLD4d8Pseudo %vreg0, 8, pred:14, pred:%noreg; mem:LD32[%A](align=8) QQPR:%vreg1 GPR:%vreg0 # CHECK: Latency : 8 # CHECK: Single Issue : true;