xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- MachineScheduler.cpp - Machine Instruction Scheduler ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // MachineScheduler schedules machine instructions after phi elimination. It
100b57cec5SDimitry Andric // preserves LiveIntervals so it can be invoked before register allocation.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h"
150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
160b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
170b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
180b57cec5SDimitry Andric #include "llvm/ADT/PriorityQueue.h"
190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
21e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h"
220b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h"
230b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/LiveInterval.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/MachinePassRegistry.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
350b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h"
360b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h"
370b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
380b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAGInstrs.h"
390b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAGMutation.h"
400b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDFS.h"
410b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
420b57cec5SDimitry Andric #include "llvm/CodeGen/SlotIndexes.h"
430b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
440b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
450b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
460b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
470b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
480b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSchedule.h"
490b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
50*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/MachineValueType.h"
510b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
52480093f4SDimitry Andric #include "llvm/InitializePasses.h"
530b57cec5SDimitry Andric #include "llvm/MC/LaneBitmask.h"
540b57cec5SDimitry Andric #include "llvm/Pass.h"
550b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
560b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
570b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
580b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
590b57cec5SDimitry Andric #include "llvm/Support/GraphWriter.h"
600b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
610b57cec5SDimitry Andric #include <algorithm>
620b57cec5SDimitry Andric #include <cassert>
630b57cec5SDimitry Andric #include <cstdint>
640b57cec5SDimitry Andric #include <iterator>
650b57cec5SDimitry Andric #include <limits>
660b57cec5SDimitry Andric #include <memory>
670b57cec5SDimitry Andric #include <string>
680b57cec5SDimitry Andric #include <tuple>
690b57cec5SDimitry Andric #include <utility>
700b57cec5SDimitry Andric #include <vector>
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric using namespace llvm;
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
750b57cec5SDimitry Andric 
76e8d8bef9SDimitry Andric STATISTIC(NumClustered, "Number of load/store pairs clustered");
77e8d8bef9SDimitry Andric 
780b57cec5SDimitry Andric namespace llvm {
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric cl::opt<bool> ForceTopDown("misched-topdown", cl::Hidden,
810b57cec5SDimitry Andric                            cl::desc("Force top-down list scheduling"));
820b57cec5SDimitry Andric cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden,
830b57cec5SDimitry Andric                             cl::desc("Force bottom-up list scheduling"));
84*0fca6ea1SDimitry Andric namespace MISchedPostRASched {
85*0fca6ea1SDimitry Andric enum Direction {
86*0fca6ea1SDimitry Andric   TopDown,
87*0fca6ea1SDimitry Andric   BottomUp,
88*0fca6ea1SDimitry Andric   Bidirectional,
89*0fca6ea1SDimitry Andric };
90*0fca6ea1SDimitry Andric } // end namespace MISchedPostRASched
91*0fca6ea1SDimitry Andric cl::opt<MISchedPostRASched::Direction> PostRADirection(
92*0fca6ea1SDimitry Andric     "misched-postra-direction", cl::Hidden,
93*0fca6ea1SDimitry Andric     cl::desc("Post reg-alloc list scheduling direction"),
94*0fca6ea1SDimitry Andric     // Default to top-down because it was implemented first and existing targets
95*0fca6ea1SDimitry Andric     // expect that behavior by default.
96*0fca6ea1SDimitry Andric     cl::init(MISchedPostRASched::TopDown),
97*0fca6ea1SDimitry Andric     cl::values(
98*0fca6ea1SDimitry Andric         clEnumValN(MISchedPostRASched::TopDown, "topdown",
99*0fca6ea1SDimitry Andric                    "Force top-down post reg-alloc list scheduling"),
100*0fca6ea1SDimitry Andric         clEnumValN(MISchedPostRASched::BottomUp, "bottomup",
101*0fca6ea1SDimitry Andric                    "Force bottom-up post reg-alloc list scheduling"),
102*0fca6ea1SDimitry Andric         clEnumValN(MISchedPostRASched::Bidirectional, "bidirectional",
103*0fca6ea1SDimitry Andric                    "Force bidirectional post reg-alloc list scheduling")));
1040b57cec5SDimitry Andric cl::opt<bool>
1050b57cec5SDimitry Andric DumpCriticalPathLength("misched-dcpl", cl::Hidden,
1060b57cec5SDimitry Andric                        cl::desc("Print critical path length to stdout"));
1070b57cec5SDimitry Andric 
1088bcb0991SDimitry Andric cl::opt<bool> VerifyScheduling(
1098bcb0991SDimitry Andric     "verify-misched", cl::Hidden,
1108bcb0991SDimitry Andric     cl::desc("Verify machine instrs before and after machine scheduling"));
1118bcb0991SDimitry Andric 
1120eae32dcSDimitry Andric #ifndef NDEBUG
1130eae32dcSDimitry Andric cl::opt<bool> ViewMISchedDAGs(
1140eae32dcSDimitry Andric     "view-misched-dags", cl::Hidden,
1150eae32dcSDimitry Andric     cl::desc("Pop up a window to show MISched dags after they are processed"));
116753f127fSDimitry Andric cl::opt<bool> PrintDAGs("misched-print-dags", cl::Hidden,
117753f127fSDimitry Andric                         cl::desc("Print schedule DAGs"));
118bdd1243dSDimitry Andric cl::opt<bool> MISchedDumpReservedCycles(
119bdd1243dSDimitry Andric     "misched-dump-reserved-cycles", cl::Hidden, cl::init(false),
120bdd1243dSDimitry Andric     cl::desc("Dump resource usage at schedule boundary."));
12106c3fb27SDimitry Andric cl::opt<bool> MischedDetailResourceBooking(
12206c3fb27SDimitry Andric     "misched-detail-resource-booking", cl::Hidden, cl::init(false),
12306c3fb27SDimitry Andric     cl::desc("Show details of invoking getNextResoufceCycle."));
1240eae32dcSDimitry Andric #else
1250eae32dcSDimitry Andric const bool ViewMISchedDAGs = false;
126753f127fSDimitry Andric const bool PrintDAGs = false;
12706c3fb27SDimitry Andric const bool MischedDetailResourceBooking = false;
128bdd1243dSDimitry Andric #ifdef LLVM_ENABLE_DUMP
129bdd1243dSDimitry Andric const bool MISchedDumpReservedCycles = false;
130bdd1243dSDimitry Andric #endif // LLVM_ENABLE_DUMP
1310eae32dcSDimitry Andric #endif // NDEBUG
1320eae32dcSDimitry Andric 
1330b57cec5SDimitry Andric } // end namespace llvm
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric #ifndef NDEBUG
1360b57cec5SDimitry Andric /// In some situations a few uninteresting nodes depend on nearly all other
1370b57cec5SDimitry Andric /// nodes in the graph, provide a cutoff to hide them.
1380b57cec5SDimitry Andric static cl::opt<unsigned> ViewMISchedCutoff("view-misched-cutoff", cl::Hidden,
1390b57cec5SDimitry Andric   cl::desc("Hide nodes with more predecessor/successor than cutoff"));
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric static cl::opt<unsigned> MISchedCutoff("misched-cutoff", cl::Hidden,
1420b57cec5SDimitry Andric   cl::desc("Stop scheduling after N instructions"), cl::init(~0U));
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric static cl::opt<std::string> SchedOnlyFunc("misched-only-func", cl::Hidden,
1450b57cec5SDimitry Andric   cl::desc("Only schedule this function"));
1460b57cec5SDimitry Andric static cl::opt<unsigned> SchedOnlyBlock("misched-only-block", cl::Hidden,
1470b57cec5SDimitry Andric                                         cl::desc("Only schedule this MBB#"));
1480b57cec5SDimitry Andric #endif // NDEBUG
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric /// Avoid quadratic complexity in unusually large basic blocks by limiting the
1510b57cec5SDimitry Andric /// size of the ready lists.
1520b57cec5SDimitry Andric static cl::opt<unsigned> ReadyListLimit("misched-limit", cl::Hidden,
1530b57cec5SDimitry Andric   cl::desc("Limit ready list to N instructions"), cl::init(256));
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric static cl::opt<bool> EnableRegPressure("misched-regpressure", cl::Hidden,
1560b57cec5SDimitry Andric   cl::desc("Enable register pressure scheduling."), cl::init(true));
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric static cl::opt<bool> EnableCyclicPath("misched-cyclicpath", cl::Hidden,
1590b57cec5SDimitry Andric   cl::desc("Enable cyclic critical path analysis."), cl::init(true));
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric static cl::opt<bool> EnableMemOpCluster("misched-cluster", cl::Hidden,
1620b57cec5SDimitry Andric                                         cl::desc("Enable memop clustering."),
1630b57cec5SDimitry Andric                                         cl::init(true));
164e8d8bef9SDimitry Andric static cl::opt<bool>
165e8d8bef9SDimitry Andric     ForceFastCluster("force-fast-cluster", cl::Hidden,
166e8d8bef9SDimitry Andric                      cl::desc("Switch to fast cluster algorithm with the lost "
167e8d8bef9SDimitry Andric                               "of some fusion opportunities"),
168e8d8bef9SDimitry Andric                      cl::init(false));
169e8d8bef9SDimitry Andric static cl::opt<unsigned>
170e8d8bef9SDimitry Andric     FastClusterThreshold("fast-cluster-threshold", cl::Hidden,
171e8d8bef9SDimitry Andric                          cl::desc("The threshold for fast cluster"),
172e8d8bef9SDimitry Andric                          cl::init(1000));
1730b57cec5SDimitry Andric 
17406c3fb27SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
17506c3fb27SDimitry Andric static cl::opt<bool> MISchedDumpScheduleTrace(
17606c3fb27SDimitry Andric     "misched-dump-schedule-trace", cl::Hidden, cl::init(false),
17706c3fb27SDimitry Andric     cl::desc("Dump resource usage at schedule boundary."));
17806c3fb27SDimitry Andric static cl::opt<unsigned>
17906c3fb27SDimitry Andric     HeaderColWidth("misched-dump-schedule-trace-col-header-width", cl::Hidden,
18006c3fb27SDimitry Andric                    cl::desc("Set width of the columns with "
18106c3fb27SDimitry Andric                             "the resources and schedule units"),
18206c3fb27SDimitry Andric                    cl::init(19));
18306c3fb27SDimitry Andric static cl::opt<unsigned>
18406c3fb27SDimitry Andric     ColWidth("misched-dump-schedule-trace-col-width", cl::Hidden,
18506c3fb27SDimitry Andric              cl::desc("Set width of the columns showing resource booking."),
18606c3fb27SDimitry Andric              cl::init(5));
18706c3fb27SDimitry Andric static cl::opt<bool> MISchedSortResourcesInTrace(
18806c3fb27SDimitry Andric     "misched-sort-resources-in-trace", cl::Hidden, cl::init(true),
18906c3fb27SDimitry Andric     cl::desc("Sort the resources printed in the dump trace"));
19006c3fb27SDimitry Andric #endif
19106c3fb27SDimitry Andric 
19206c3fb27SDimitry Andric static cl::opt<unsigned>
19306c3fb27SDimitry Andric     MIResourceCutOff("misched-resource-cutoff", cl::Hidden,
19406c3fb27SDimitry Andric                      cl::desc("Number of intervals to track"), cl::init(10));
19506c3fb27SDimitry Andric 
1960b57cec5SDimitry Andric // DAG subtrees must have at least this many nodes.
1970b57cec5SDimitry Andric static const unsigned MinSubtreeSize = 8;
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric // Pin the vtables to this file.
2000b57cec5SDimitry Andric void MachineSchedStrategy::anchor() {}
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric void ScheduleDAGMutation::anchor() {}
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2050b57cec5SDimitry Andric // Machine Instruction Scheduling Pass and Registry
2060b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric MachineSchedContext::MachineSchedContext() {
2090b57cec5SDimitry Andric   RegClassInfo = new RegisterClassInfo();
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric MachineSchedContext::~MachineSchedContext() {
2130b57cec5SDimitry Andric   delete RegClassInfo;
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric namespace {
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric /// Base class for a machine scheduler class that can run at any point.
2190b57cec5SDimitry Andric class MachineSchedulerBase : public MachineSchedContext,
2200b57cec5SDimitry Andric                              public MachineFunctionPass {
2210b57cec5SDimitry Andric public:
2220b57cec5SDimitry Andric   MachineSchedulerBase(char &ID): MachineFunctionPass(ID) {}
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   void print(raw_ostream &O, const Module* = nullptr) const override;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric protected:
2270b57cec5SDimitry Andric   void scheduleRegions(ScheduleDAGInstrs &Scheduler, bool FixKillFlags);
2280b57cec5SDimitry Andric };
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric /// MachineScheduler runs after coalescing and before register allocation.
2310b57cec5SDimitry Andric class MachineScheduler : public MachineSchedulerBase {
2320b57cec5SDimitry Andric public:
2330b57cec5SDimitry Andric   MachineScheduler();
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction&) override;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   static char ID; // Class identification, replacement for typeinfo
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric protected:
2420b57cec5SDimitry Andric   ScheduleDAGInstrs *createMachineScheduler();
2430b57cec5SDimitry Andric };
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric /// PostMachineScheduler runs after shortly before code emission.
2460b57cec5SDimitry Andric class PostMachineScheduler : public MachineSchedulerBase {
2470b57cec5SDimitry Andric public:
2480b57cec5SDimitry Andric   PostMachineScheduler();
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction&) override;
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   static char ID; // Class identification, replacement for typeinfo
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric protected:
2570b57cec5SDimitry Andric   ScheduleDAGInstrs *createPostMachineScheduler();
2580b57cec5SDimitry Andric };
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric } // end anonymous namespace
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric char MachineScheduler::ID = 0;
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric char &llvm::MachineSchedulerID = MachineScheduler::ID;
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(MachineScheduler, DEBUG_TYPE,
2670b57cec5SDimitry Andric                       "Machine Instruction Scheduler", false, false)
2680b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
269*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
270*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
271*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass)
272*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
2730b57cec5SDimitry Andric INITIALIZE_PASS_END(MachineScheduler, DEBUG_TYPE,
2740b57cec5SDimitry Andric                     "Machine Instruction Scheduler", false, false)
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric MachineScheduler::MachineScheduler() : MachineSchedulerBase(ID) {
2770b57cec5SDimitry Andric   initializeMachineSchedulerPass(*PassRegistry::getPassRegistry());
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric void MachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const {
2810b57cec5SDimitry Andric   AU.setPreservesCFG();
282*0fca6ea1SDimitry Andric   AU.addRequired<MachineDominatorTreeWrapperPass>();
283*0fca6ea1SDimitry Andric   AU.addRequired<MachineLoopInfoWrapperPass>();
2840b57cec5SDimitry Andric   AU.addRequired<AAResultsWrapperPass>();
2850b57cec5SDimitry Andric   AU.addRequired<TargetPassConfig>();
286*0fca6ea1SDimitry Andric   AU.addRequired<SlotIndexesWrapperPass>();
287*0fca6ea1SDimitry Andric   AU.addPreserved<SlotIndexesWrapperPass>();
288*0fca6ea1SDimitry Andric   AU.addRequired<LiveIntervalsWrapperPass>();
289*0fca6ea1SDimitry Andric   AU.addPreserved<LiveIntervalsWrapperPass>();
2900b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric char PostMachineScheduler::ID = 0;
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric char &llvm::PostMachineSchedulerID = PostMachineScheduler::ID;
2960b57cec5SDimitry Andric 
297e8d8bef9SDimitry Andric INITIALIZE_PASS_BEGIN(PostMachineScheduler, "postmisched",
298e8d8bef9SDimitry Andric                       "PostRA Machine Instruction Scheduler", false, false)
299*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
300*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
301e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
302e8d8bef9SDimitry Andric INITIALIZE_PASS_END(PostMachineScheduler, "postmisched",
3030b57cec5SDimitry Andric                     "PostRA Machine Instruction Scheduler", false, false)
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric PostMachineScheduler::PostMachineScheduler() : MachineSchedulerBase(ID) {
3060b57cec5SDimitry Andric   initializePostMachineSchedulerPass(*PassRegistry::getPassRegistry());
3070b57cec5SDimitry Andric }
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric void PostMachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const {
3100b57cec5SDimitry Andric   AU.setPreservesCFG();
311*0fca6ea1SDimitry Andric   AU.addRequired<MachineDominatorTreeWrapperPass>();
312*0fca6ea1SDimitry Andric   AU.addRequired<MachineLoopInfoWrapperPass>();
313480093f4SDimitry Andric   AU.addRequired<AAResultsWrapperPass>();
3140b57cec5SDimitry Andric   AU.addRequired<TargetPassConfig>();
3150b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric MachinePassRegistry<MachineSchedRegistry::ScheduleDAGCtor>
3190b57cec5SDimitry Andric     MachineSchedRegistry::Registry;
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric /// A dummy default scheduler factory indicates whether the scheduler
3220b57cec5SDimitry Andric /// is overridden on the command line.
3230b57cec5SDimitry Andric static ScheduleDAGInstrs *useDefaultMachineSched(MachineSchedContext *C) {
3240b57cec5SDimitry Andric   return nullptr;
3250b57cec5SDimitry Andric }
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric /// MachineSchedOpt allows command line selection of the scheduler.
3280b57cec5SDimitry Andric static cl::opt<MachineSchedRegistry::ScheduleDAGCtor, false,
3290b57cec5SDimitry Andric                RegisterPassParser<MachineSchedRegistry>>
3300b57cec5SDimitry Andric MachineSchedOpt("misched",
3310b57cec5SDimitry Andric                 cl::init(&useDefaultMachineSched), cl::Hidden,
3320b57cec5SDimitry Andric                 cl::desc("Machine instruction scheduler to use"));
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric static MachineSchedRegistry
3350b57cec5SDimitry Andric DefaultSchedRegistry("default", "Use the target's default scheduler choice.",
3360b57cec5SDimitry Andric                      useDefaultMachineSched);
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric static cl::opt<bool> EnableMachineSched(
3390b57cec5SDimitry Andric     "enable-misched",
3400b57cec5SDimitry Andric     cl::desc("Enable the machine instruction scheduling pass."), cl::init(true),
3410b57cec5SDimitry Andric     cl::Hidden);
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric static cl::opt<bool> EnablePostRAMachineSched(
3440b57cec5SDimitry Andric     "enable-post-misched",
3450b57cec5SDimitry Andric     cl::desc("Enable the post-ra machine instruction scheduling pass."),
3460b57cec5SDimitry Andric     cl::init(true), cl::Hidden);
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric /// Decrement this iterator until reaching the top or a non-debug instr.
3490b57cec5SDimitry Andric static MachineBasicBlock::const_iterator
3500b57cec5SDimitry Andric priorNonDebug(MachineBasicBlock::const_iterator I,
3510b57cec5SDimitry Andric               MachineBasicBlock::const_iterator Beg) {
3520b57cec5SDimitry Andric   assert(I != Beg && "reached the top of the region, cannot decrement");
3530b57cec5SDimitry Andric   while (--I != Beg) {
354fe6060f1SDimitry Andric     if (!I->isDebugOrPseudoInstr())
3550b57cec5SDimitry Andric       break;
3560b57cec5SDimitry Andric   }
3570b57cec5SDimitry Andric   return I;
3580b57cec5SDimitry Andric }
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric /// Non-const version.
3610b57cec5SDimitry Andric static MachineBasicBlock::iterator
3620b57cec5SDimitry Andric priorNonDebug(MachineBasicBlock::iterator I,
3630b57cec5SDimitry Andric               MachineBasicBlock::const_iterator Beg) {
3640b57cec5SDimitry Andric   return priorNonDebug(MachineBasicBlock::const_iterator(I), Beg)
3650b57cec5SDimitry Andric       .getNonConstIterator();
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric /// If this iterator is a debug value, increment until reaching the End or a
3690b57cec5SDimitry Andric /// non-debug instruction.
3700b57cec5SDimitry Andric static MachineBasicBlock::const_iterator
3710b57cec5SDimitry Andric nextIfDebug(MachineBasicBlock::const_iterator I,
3720b57cec5SDimitry Andric             MachineBasicBlock::const_iterator End) {
3730b57cec5SDimitry Andric   for(; I != End; ++I) {
374fe6060f1SDimitry Andric     if (!I->isDebugOrPseudoInstr())
3750b57cec5SDimitry Andric       break;
3760b57cec5SDimitry Andric   }
3770b57cec5SDimitry Andric   return I;
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric /// Non-const version.
3810b57cec5SDimitry Andric static MachineBasicBlock::iterator
3820b57cec5SDimitry Andric nextIfDebug(MachineBasicBlock::iterator I,
3830b57cec5SDimitry Andric             MachineBasicBlock::const_iterator End) {
3840b57cec5SDimitry Andric   return nextIfDebug(MachineBasicBlock::const_iterator(I), End)
3850b57cec5SDimitry Andric       .getNonConstIterator();
3860b57cec5SDimitry Andric }
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric /// Instantiate a ScheduleDAGInstrs that will be owned by the caller.
3890b57cec5SDimitry Andric ScheduleDAGInstrs *MachineScheduler::createMachineScheduler() {
3900b57cec5SDimitry Andric   // Select the scheduler, or set the default.
3910b57cec5SDimitry Andric   MachineSchedRegistry::ScheduleDAGCtor Ctor = MachineSchedOpt;
3920b57cec5SDimitry Andric   if (Ctor != useDefaultMachineSched)
3930b57cec5SDimitry Andric     return Ctor(this);
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   // Get the default scheduler set by the target for this function.
3960b57cec5SDimitry Andric   ScheduleDAGInstrs *Scheduler = PassConfig->createMachineScheduler(this);
3970b57cec5SDimitry Andric   if (Scheduler)
3980b57cec5SDimitry Andric     return Scheduler;
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   // Default to GenericScheduler.
4010b57cec5SDimitry Andric   return createGenericSchedLive(this);
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric /// Instantiate a ScheduleDAGInstrs for PostRA scheduling that will be owned by
4050b57cec5SDimitry Andric /// the caller. We don't have a command line option to override the postRA
4060b57cec5SDimitry Andric /// scheduler. The Target must configure it.
4070b57cec5SDimitry Andric ScheduleDAGInstrs *PostMachineScheduler::createPostMachineScheduler() {
4080b57cec5SDimitry Andric   // Get the postRA scheduler set by the target for this function.
4090b57cec5SDimitry Andric   ScheduleDAGInstrs *Scheduler = PassConfig->createPostMachineScheduler(this);
4100b57cec5SDimitry Andric   if (Scheduler)
4110b57cec5SDimitry Andric     return Scheduler;
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   // Default to GenericScheduler.
4140b57cec5SDimitry Andric   return createGenericSchedPostRA(this);
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric /// Top-level MachineScheduler pass driver.
4180b57cec5SDimitry Andric ///
4190b57cec5SDimitry Andric /// Visit blocks in function order. Divide each block into scheduling regions
4200b57cec5SDimitry Andric /// and visit them bottom-up. Visiting regions bottom-up is not required, but is
4210b57cec5SDimitry Andric /// consistent with the DAG builder, which traverses the interior of the
4220b57cec5SDimitry Andric /// scheduling regions bottom-up.
4230b57cec5SDimitry Andric ///
4240b57cec5SDimitry Andric /// This design avoids exposing scheduling boundaries to the DAG builder,
4250b57cec5SDimitry Andric /// simplifying the DAG builder's support for "special" target instructions.
4260b57cec5SDimitry Andric /// At the same time the design allows target schedulers to operate across
4270b57cec5SDimitry Andric /// scheduling boundaries, for example to bundle the boundary instructions
4280b57cec5SDimitry Andric /// without reordering them. This creates complexity, because the target
4290b57cec5SDimitry Andric /// scheduler must update the RegionBegin and RegionEnd positions cached by
4300b57cec5SDimitry Andric /// ScheduleDAGInstrs whenever adding or removing instructions. A much simpler
4310b57cec5SDimitry Andric /// design would be to split blocks at scheduling boundaries, but LLVM has a
4320b57cec5SDimitry Andric /// general bias against block splitting purely for implementation simplicity.
4330b57cec5SDimitry Andric bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) {
4340b57cec5SDimitry Andric   if (skipFunction(mf.getFunction()))
4350b57cec5SDimitry Andric     return false;
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   if (EnableMachineSched.getNumOccurrences()) {
4380b57cec5SDimitry Andric     if (!EnableMachineSched)
4390b57cec5SDimitry Andric       return false;
4400b57cec5SDimitry Andric   } else if (!mf.getSubtarget().enableMachineScheduler())
4410b57cec5SDimitry Andric     return false;
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Before MISched:\n"; mf.print(dbgs()));
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   // Initialize the context of the pass.
4460b57cec5SDimitry Andric   MF = &mf;
447*0fca6ea1SDimitry Andric   MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
448*0fca6ea1SDimitry Andric   MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
4490b57cec5SDimitry Andric   PassConfig = &getAnalysis<TargetPassConfig>();
4500b57cec5SDimitry Andric   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
4510b57cec5SDimitry Andric 
452*0fca6ea1SDimitry Andric   LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   if (VerifyScheduling) {
4550b57cec5SDimitry Andric     LLVM_DEBUG(LIS->dump());
4560b57cec5SDimitry Andric     MF->verify(this, "Before machine scheduling.");
4570b57cec5SDimitry Andric   }
4580b57cec5SDimitry Andric   RegClassInfo->runOnMachineFunction(*MF);
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   // Instantiate the selected scheduler for this target, function, and
4610b57cec5SDimitry Andric   // optimization level.
4620b57cec5SDimitry Andric   std::unique_ptr<ScheduleDAGInstrs> Scheduler(createMachineScheduler());
463*0fca6ea1SDimitry Andric   ScheduleDAGMI::DumpDirection D;
464*0fca6ea1SDimitry Andric   if (ForceTopDown)
465*0fca6ea1SDimitry Andric     D = ScheduleDAGMI::DumpDirection::TopDown;
466*0fca6ea1SDimitry Andric   else if (ForceBottomUp)
467*0fca6ea1SDimitry Andric     D = ScheduleDAGMI::DumpDirection::BottomUp;
468*0fca6ea1SDimitry Andric   else
469*0fca6ea1SDimitry Andric     D = ScheduleDAGMI::DumpDirection::Bidirectional;
470*0fca6ea1SDimitry Andric   Scheduler->setDumpDirection(D);
4710b57cec5SDimitry Andric   scheduleRegions(*Scheduler, false);
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric   LLVM_DEBUG(LIS->dump());
4740b57cec5SDimitry Andric   if (VerifyScheduling)
4750b57cec5SDimitry Andric     MF->verify(this, "After machine scheduling.");
4760b57cec5SDimitry Andric   return true;
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) {
4800b57cec5SDimitry Andric   if (skipFunction(mf.getFunction()))
4810b57cec5SDimitry Andric     return false;
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   if (EnablePostRAMachineSched.getNumOccurrences()) {
4840b57cec5SDimitry Andric     if (!EnablePostRAMachineSched)
4850b57cec5SDimitry Andric       return false;
486480093f4SDimitry Andric   } else if (!mf.getSubtarget().enablePostRAMachineScheduler()) {
4870b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Subtarget disables post-MI-sched.\n");
4880b57cec5SDimitry Andric     return false;
4890b57cec5SDimitry Andric   }
4900b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Before post-MI-sched:\n"; mf.print(dbgs()));
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric   // Initialize the context of the pass.
4930b57cec5SDimitry Andric   MF = &mf;
494*0fca6ea1SDimitry Andric   MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
4950b57cec5SDimitry Andric   PassConfig = &getAnalysis<TargetPassConfig>();
496480093f4SDimitry Andric   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric   if (VerifyScheduling)
4990b57cec5SDimitry Andric     MF->verify(this, "Before post machine scheduling.");
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   // Instantiate the selected scheduler for this target, function, and
5020b57cec5SDimitry Andric   // optimization level.
5030b57cec5SDimitry Andric   std::unique_ptr<ScheduleDAGInstrs> Scheduler(createPostMachineScheduler());
504*0fca6ea1SDimitry Andric   ScheduleDAGMI::DumpDirection D;
505*0fca6ea1SDimitry Andric   if (PostRADirection == MISchedPostRASched::TopDown)
506*0fca6ea1SDimitry Andric     D = ScheduleDAGMI::DumpDirection::TopDown;
507*0fca6ea1SDimitry Andric   else if (PostRADirection == MISchedPostRASched::BottomUp)
508*0fca6ea1SDimitry Andric     D = ScheduleDAGMI::DumpDirection::BottomUp;
509*0fca6ea1SDimitry Andric   else
510*0fca6ea1SDimitry Andric     D = ScheduleDAGMI::DumpDirection::Bidirectional;
511*0fca6ea1SDimitry Andric   Scheduler->setDumpDirection(D);
5120b57cec5SDimitry Andric   scheduleRegions(*Scheduler, true);
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   if (VerifyScheduling)
5150b57cec5SDimitry Andric     MF->verify(this, "After post machine scheduling.");
5160b57cec5SDimitry Andric   return true;
5170b57cec5SDimitry Andric }
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric /// Return true of the given instruction should not be included in a scheduling
5200b57cec5SDimitry Andric /// region.
5210b57cec5SDimitry Andric ///
5220b57cec5SDimitry Andric /// MachineScheduler does not currently support scheduling across calls. To
5230b57cec5SDimitry Andric /// handle calls, the DAG builder needs to be modified to create register
5240b57cec5SDimitry Andric /// anti/output dependencies on the registers clobbered by the call's regmask
5250b57cec5SDimitry Andric /// operand. In PreRA scheduling, the stack pointer adjustment already prevents
5260b57cec5SDimitry Andric /// scheduling across calls. In PostRA scheduling, we need the isCall to enforce
5270b57cec5SDimitry Andric /// the boundary, but there would be no benefit to postRA scheduling across
5280b57cec5SDimitry Andric /// calls this late anyway.
5290b57cec5SDimitry Andric static bool isSchedBoundary(MachineBasicBlock::iterator MI,
5300b57cec5SDimitry Andric                             MachineBasicBlock *MBB,
5310b57cec5SDimitry Andric                             MachineFunction *MF,
5320b57cec5SDimitry Andric                             const TargetInstrInfo *TII) {
5330b57cec5SDimitry Andric   return MI->isCall() || TII->isSchedulingBoundary(*MI, MBB, *MF);
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric /// A region of an MBB for scheduling.
5370b57cec5SDimitry Andric namespace {
5380b57cec5SDimitry Andric struct SchedRegion {
5390b57cec5SDimitry Andric   /// RegionBegin is the first instruction in the scheduling region, and
5400b57cec5SDimitry Andric   /// RegionEnd is either MBB->end() or the scheduling boundary after the
5410b57cec5SDimitry Andric   /// last instruction in the scheduling region. These iterators cannot refer
5420b57cec5SDimitry Andric   /// to instructions outside of the identified scheduling region because
5430b57cec5SDimitry Andric   /// those may be reordered before scheduling this region.
5440b57cec5SDimitry Andric   MachineBasicBlock::iterator RegionBegin;
5450b57cec5SDimitry Andric   MachineBasicBlock::iterator RegionEnd;
5460b57cec5SDimitry Andric   unsigned NumRegionInstrs;
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   SchedRegion(MachineBasicBlock::iterator B, MachineBasicBlock::iterator E,
5490b57cec5SDimitry Andric               unsigned N) :
5500b57cec5SDimitry Andric     RegionBegin(B), RegionEnd(E), NumRegionInstrs(N) {}
5510b57cec5SDimitry Andric };
5520b57cec5SDimitry Andric } // end anonymous namespace
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric using MBBRegionsVector = SmallVector<SchedRegion, 16>;
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric static void
5570b57cec5SDimitry Andric getSchedRegions(MachineBasicBlock *MBB,
5580b57cec5SDimitry Andric                 MBBRegionsVector &Regions,
5590b57cec5SDimitry Andric                 bool RegionsTopDown) {
5600b57cec5SDimitry Andric   MachineFunction *MF = MBB->getParent();
5610b57cec5SDimitry Andric   const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric   MachineBasicBlock::iterator I = nullptr;
5640b57cec5SDimitry Andric   for(MachineBasicBlock::iterator RegionEnd = MBB->end();
5650b57cec5SDimitry Andric       RegionEnd != MBB->begin(); RegionEnd = I) {
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric     // Avoid decrementing RegionEnd for blocks with no terminator.
5680b57cec5SDimitry Andric     if (RegionEnd != MBB->end() ||
5690b57cec5SDimitry Andric         isSchedBoundary(&*std::prev(RegionEnd), &*MBB, MF, TII)) {
5700b57cec5SDimitry Andric       --RegionEnd;
5710b57cec5SDimitry Andric     }
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric     // The next region starts above the previous region. Look backward in the
5740b57cec5SDimitry Andric     // instruction stream until we find the nearest boundary.
5750b57cec5SDimitry Andric     unsigned NumRegionInstrs = 0;
5760b57cec5SDimitry Andric     I = RegionEnd;
5770b57cec5SDimitry Andric     for (;I != MBB->begin(); --I) {
5780b57cec5SDimitry Andric       MachineInstr &MI = *std::prev(I);
5790b57cec5SDimitry Andric       if (isSchedBoundary(&MI, &*MBB, MF, TII))
5800b57cec5SDimitry Andric         break;
581fe6060f1SDimitry Andric       if (!MI.isDebugOrPseudoInstr()) {
5820b57cec5SDimitry Andric         // MBB::size() uses instr_iterator to count. Here we need a bundle to
5830b57cec5SDimitry Andric         // count as a single instruction.
5840b57cec5SDimitry Andric         ++NumRegionInstrs;
5850b57cec5SDimitry Andric       }
5860b57cec5SDimitry Andric     }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric     // It's possible we found a scheduling region that only has debug
5890b57cec5SDimitry Andric     // instructions. Don't bother scheduling these.
5900b57cec5SDimitry Andric     if (NumRegionInstrs != 0)
5910b57cec5SDimitry Andric       Regions.push_back(SchedRegion(I, RegionEnd, NumRegionInstrs));
5920b57cec5SDimitry Andric   }
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric   if (RegionsTopDown)
5950b57cec5SDimitry Andric     std::reverse(Regions.begin(), Regions.end());
5960b57cec5SDimitry Andric }
5970b57cec5SDimitry Andric 
5980b57cec5SDimitry Andric /// Main driver for both MachineScheduler and PostMachineScheduler.
5990b57cec5SDimitry Andric void MachineSchedulerBase::scheduleRegions(ScheduleDAGInstrs &Scheduler,
6000b57cec5SDimitry Andric                                            bool FixKillFlags) {
6010b57cec5SDimitry Andric   // Visit all machine basic blocks.
6020b57cec5SDimitry Andric   //
6030b57cec5SDimitry Andric   // TODO: Visit blocks in global postorder or postorder within the bottom-up
6040b57cec5SDimitry Andric   // loop tree. Then we can optionally compute global RegPressure.
6050b57cec5SDimitry Andric   for (MachineFunction::iterator MBB = MF->begin(), MBBEnd = MF->end();
6060b57cec5SDimitry Andric        MBB != MBBEnd; ++MBB) {
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric     Scheduler.startBlock(&*MBB);
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric #ifndef NDEBUG
6110b57cec5SDimitry Andric     if (SchedOnlyFunc.getNumOccurrences() && SchedOnlyFunc != MF->getName())
6120b57cec5SDimitry Andric       continue;
6130b57cec5SDimitry Andric     if (SchedOnlyBlock.getNumOccurrences()
6140b57cec5SDimitry Andric         && (int)SchedOnlyBlock != MBB->getNumber())
6150b57cec5SDimitry Andric       continue;
6160b57cec5SDimitry Andric #endif
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric     // Break the block into scheduling regions [I, RegionEnd). RegionEnd
6190b57cec5SDimitry Andric     // points to the scheduling boundary at the bottom of the region. The DAG
6200b57cec5SDimitry Andric     // does not include RegionEnd, but the region does (i.e. the next
6210b57cec5SDimitry Andric     // RegionEnd is above the previous RegionBegin). If the current block has
6220b57cec5SDimitry Andric     // no terminator then RegionEnd == MBB->end() for the bottom region.
6230b57cec5SDimitry Andric     //
6240b57cec5SDimitry Andric     // All the regions of MBB are first found and stored in MBBRegions, which
6250b57cec5SDimitry Andric     // will be processed (MBB) top-down if initialized with true.
6260b57cec5SDimitry Andric     //
6270b57cec5SDimitry Andric     // The Scheduler may insert instructions during either schedule() or
6280b57cec5SDimitry Andric     // exitRegion(), even for empty regions. So the local iterators 'I' and
6290b57cec5SDimitry Andric     // 'RegionEnd' are invalid across these calls. Instructions must not be
6300b57cec5SDimitry Andric     // added to other regions than the current one without updating MBBRegions.
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric     MBBRegionsVector MBBRegions;
6330b57cec5SDimitry Andric     getSchedRegions(&*MBB, MBBRegions, Scheduler.doMBBSchedRegionsTopDown());
6340eae32dcSDimitry Andric     for (const SchedRegion &R : MBBRegions) {
6350eae32dcSDimitry Andric       MachineBasicBlock::iterator I = R.RegionBegin;
6360eae32dcSDimitry Andric       MachineBasicBlock::iterator RegionEnd = R.RegionEnd;
6370eae32dcSDimitry Andric       unsigned NumRegionInstrs = R.NumRegionInstrs;
6380b57cec5SDimitry Andric 
6390b57cec5SDimitry Andric       // Notify the scheduler of the region, even if we may skip scheduling
6400b57cec5SDimitry Andric       // it. Perhaps it still needs to be bundled.
6410b57cec5SDimitry Andric       Scheduler.enterRegion(&*MBB, I, RegionEnd, NumRegionInstrs);
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric       // Skip empty scheduling regions (0 or 1 schedulable instructions).
6440b57cec5SDimitry Andric       if (I == RegionEnd || I == std::prev(RegionEnd)) {
6450b57cec5SDimitry Andric         // Close the current region. Bundle the terminator if needed.
6460b57cec5SDimitry Andric         // This invalidates 'RegionEnd' and 'I'.
6470b57cec5SDimitry Andric         Scheduler.exitRegion();
6480b57cec5SDimitry Andric         continue;
6490b57cec5SDimitry Andric       }
6500b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
6510b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << MF->getName() << ":" << printMBBReference(*MBB)
6520b57cec5SDimitry Andric                         << " " << MBB->getName() << "\n  From: " << *I
6530b57cec5SDimitry Andric                         << "    To: ";
6540b57cec5SDimitry Andric                  if (RegionEnd != MBB->end()) dbgs() << *RegionEnd;
655349cc55cSDimitry Andric                  else dbgs() << "End\n";
6560b57cec5SDimitry Andric                  dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
6570b57cec5SDimitry Andric       if (DumpCriticalPathLength) {
6580b57cec5SDimitry Andric         errs() << MF->getName();
6590b57cec5SDimitry Andric         errs() << ":%bb. " << MBB->getNumber();
6600b57cec5SDimitry Andric         errs() << " " << MBB->getName() << " \n";
6610b57cec5SDimitry Andric       }
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric       // Schedule a region: possibly reorder instructions.
6640b57cec5SDimitry Andric       // This invalidates the original region iterators.
6650b57cec5SDimitry Andric       Scheduler.schedule();
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric       // Close the current region.
6680b57cec5SDimitry Andric       Scheduler.exitRegion();
6690b57cec5SDimitry Andric     }
6700b57cec5SDimitry Andric     Scheduler.finishBlock();
6710b57cec5SDimitry Andric     // FIXME: Ideally, no further passes should rely on kill flags. However,
6720b57cec5SDimitry Andric     // thumb2 size reduction is currently an exception, so the PostMIScheduler
6730b57cec5SDimitry Andric     // needs to do this.
6740b57cec5SDimitry Andric     if (FixKillFlags)
6750b57cec5SDimitry Andric       Scheduler.fixupKills(*MBB);
6760b57cec5SDimitry Andric   }
6770b57cec5SDimitry Andric   Scheduler.finalizeSchedule();
6780b57cec5SDimitry Andric }
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric void MachineSchedulerBase::print(raw_ostream &O, const Module* m) const {
6810b57cec5SDimitry Andric   // unimplemented
6820b57cec5SDimitry Andric }
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
6850b57cec5SDimitry Andric LLVM_DUMP_METHOD void ReadyQueue::dump() const {
6860b57cec5SDimitry Andric   dbgs() << "Queue " << Name << ": ";
6870b57cec5SDimitry Andric   for (const SUnit *SU : Queue)
6880b57cec5SDimitry Andric     dbgs() << SU->NodeNum << " ";
6890b57cec5SDimitry Andric   dbgs() << "\n";
6900b57cec5SDimitry Andric }
6910b57cec5SDimitry Andric #endif
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6940b57cec5SDimitry Andric // ScheduleDAGMI - Basic machine instruction scheduling. This is
6950b57cec5SDimitry Andric // independent of PreRA/PostRA scheduling and involves no extra book-keeping for
6960b57cec5SDimitry Andric // virtual registers.
6970b57cec5SDimitry Andric // ===----------------------------------------------------------------------===/
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric // Provide a vtable anchor.
7000b57cec5SDimitry Andric ScheduleDAGMI::~ScheduleDAGMI() = default;
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric /// ReleaseSucc - Decrement the NumPredsLeft count of a successor. When
7030b57cec5SDimitry Andric /// NumPredsLeft reaches zero, release the successor node.
7040b57cec5SDimitry Andric ///
7050b57cec5SDimitry Andric /// FIXME: Adjust SuccSU height based on MinLatency.
7060b57cec5SDimitry Andric void ScheduleDAGMI::releaseSucc(SUnit *SU, SDep *SuccEdge) {
7070b57cec5SDimitry Andric   SUnit *SuccSU = SuccEdge->getSUnit();
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric   if (SuccEdge->isWeak()) {
7100b57cec5SDimitry Andric     --SuccSU->WeakPredsLeft;
7110b57cec5SDimitry Andric     if (SuccEdge->isCluster())
7120b57cec5SDimitry Andric       NextClusterSucc = SuccSU;
7130b57cec5SDimitry Andric     return;
7140b57cec5SDimitry Andric   }
7150b57cec5SDimitry Andric #ifndef NDEBUG
7160b57cec5SDimitry Andric   if (SuccSU->NumPredsLeft == 0) {
7170b57cec5SDimitry Andric     dbgs() << "*** Scheduling failed! ***\n";
7180b57cec5SDimitry Andric     dumpNode(*SuccSU);
7190b57cec5SDimitry Andric     dbgs() << " has been released too many times!\n";
7200b57cec5SDimitry Andric     llvm_unreachable(nullptr);
7210b57cec5SDimitry Andric   }
7220b57cec5SDimitry Andric #endif
7230b57cec5SDimitry Andric   // SU->TopReadyCycle was set to CurrCycle when it was scheduled. However,
7240b57cec5SDimitry Andric   // CurrCycle may have advanced since then.
7250b57cec5SDimitry Andric   if (SuccSU->TopReadyCycle < SU->TopReadyCycle + SuccEdge->getLatency())
7260b57cec5SDimitry Andric     SuccSU->TopReadyCycle = SU->TopReadyCycle + SuccEdge->getLatency();
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric   --SuccSU->NumPredsLeft;
7290b57cec5SDimitry Andric   if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU)
7300b57cec5SDimitry Andric     SchedImpl->releaseTopNode(SuccSU);
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric /// releaseSuccessors - Call releaseSucc on each of SU's successors.
7340b57cec5SDimitry Andric void ScheduleDAGMI::releaseSuccessors(SUnit *SU) {
7350b57cec5SDimitry Andric   for (SDep &Succ : SU->Succs)
7360b57cec5SDimitry Andric     releaseSucc(SU, &Succ);
7370b57cec5SDimitry Andric }
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric /// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. When
7400b57cec5SDimitry Andric /// NumSuccsLeft reaches zero, release the predecessor node.
7410b57cec5SDimitry Andric ///
7420b57cec5SDimitry Andric /// FIXME: Adjust PredSU height based on MinLatency.
7430b57cec5SDimitry Andric void ScheduleDAGMI::releasePred(SUnit *SU, SDep *PredEdge) {
7440b57cec5SDimitry Andric   SUnit *PredSU = PredEdge->getSUnit();
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric   if (PredEdge->isWeak()) {
7470b57cec5SDimitry Andric     --PredSU->WeakSuccsLeft;
7480b57cec5SDimitry Andric     if (PredEdge->isCluster())
7490b57cec5SDimitry Andric       NextClusterPred = PredSU;
7500b57cec5SDimitry Andric     return;
7510b57cec5SDimitry Andric   }
7520b57cec5SDimitry Andric #ifndef NDEBUG
7530b57cec5SDimitry Andric   if (PredSU->NumSuccsLeft == 0) {
7540b57cec5SDimitry Andric     dbgs() << "*** Scheduling failed! ***\n";
7550b57cec5SDimitry Andric     dumpNode(*PredSU);
7560b57cec5SDimitry Andric     dbgs() << " has been released too many times!\n";
7570b57cec5SDimitry Andric     llvm_unreachable(nullptr);
7580b57cec5SDimitry Andric   }
7590b57cec5SDimitry Andric #endif
7600b57cec5SDimitry Andric   // SU->BotReadyCycle was set to CurrCycle when it was scheduled. However,
7610b57cec5SDimitry Andric   // CurrCycle may have advanced since then.
7620b57cec5SDimitry Andric   if (PredSU->BotReadyCycle < SU->BotReadyCycle + PredEdge->getLatency())
7630b57cec5SDimitry Andric     PredSU->BotReadyCycle = SU->BotReadyCycle + PredEdge->getLatency();
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric   --PredSU->NumSuccsLeft;
7660b57cec5SDimitry Andric   if (PredSU->NumSuccsLeft == 0 && PredSU != &EntrySU)
7670b57cec5SDimitry Andric     SchedImpl->releaseBottomNode(PredSU);
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric /// releasePredecessors - Call releasePred on each of SU's predecessors.
7710b57cec5SDimitry Andric void ScheduleDAGMI::releasePredecessors(SUnit *SU) {
7720b57cec5SDimitry Andric   for (SDep &Pred : SU->Preds)
7730b57cec5SDimitry Andric     releasePred(SU, &Pred);
7740b57cec5SDimitry Andric }
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric void ScheduleDAGMI::startBlock(MachineBasicBlock *bb) {
7770b57cec5SDimitry Andric   ScheduleDAGInstrs::startBlock(bb);
7780b57cec5SDimitry Andric   SchedImpl->enterMBB(bb);
7790b57cec5SDimitry Andric }
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric void ScheduleDAGMI::finishBlock() {
7820b57cec5SDimitry Andric   SchedImpl->leaveMBB();
7830b57cec5SDimitry Andric   ScheduleDAGInstrs::finishBlock();
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric 
7865f757f3fSDimitry Andric /// enterRegion - Called back from PostMachineScheduler::runOnMachineFunction
7875f757f3fSDimitry Andric /// after crossing a scheduling boundary. [begin, end) includes all instructions
7885f757f3fSDimitry Andric /// in the region, including the boundary itself and single-instruction regions
7890b57cec5SDimitry Andric /// that don't get scheduled.
7900b57cec5SDimitry Andric void ScheduleDAGMI::enterRegion(MachineBasicBlock *bb,
7910b57cec5SDimitry Andric                                      MachineBasicBlock::iterator begin,
7920b57cec5SDimitry Andric                                      MachineBasicBlock::iterator end,
7930b57cec5SDimitry Andric                                      unsigned regioninstrs)
7940b57cec5SDimitry Andric {
7950b57cec5SDimitry Andric   ScheduleDAGInstrs::enterRegion(bb, begin, end, regioninstrs);
7960b57cec5SDimitry Andric 
7970b57cec5SDimitry Andric   SchedImpl->initPolicy(begin, end, regioninstrs);
7980b57cec5SDimitry Andric }
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric /// This is normally called from the main scheduler loop but may also be invoked
8010b57cec5SDimitry Andric /// by the scheduling strategy to perform additional code motion.
8020b57cec5SDimitry Andric void ScheduleDAGMI::moveInstruction(
8030b57cec5SDimitry Andric   MachineInstr *MI, MachineBasicBlock::iterator InsertPos) {
8040b57cec5SDimitry Andric   // Advance RegionBegin if the first instruction moves down.
8050b57cec5SDimitry Andric   if (&*RegionBegin == MI)
8060b57cec5SDimitry Andric     ++RegionBegin;
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   // Update the instruction stream.
8090b57cec5SDimitry Andric   BB->splice(InsertPos, BB, MI);
8100b57cec5SDimitry Andric 
8110b57cec5SDimitry Andric   // Update LiveIntervals
8120b57cec5SDimitry Andric   if (LIS)
8130b57cec5SDimitry Andric     LIS->handleMove(*MI, /*UpdateFlags=*/true);
8140b57cec5SDimitry Andric 
8150b57cec5SDimitry Andric   // Recede RegionBegin if an instruction moves above the first.
8160b57cec5SDimitry Andric   if (RegionBegin == InsertPos)
8170b57cec5SDimitry Andric     RegionBegin = MI;
8180b57cec5SDimitry Andric }
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric bool ScheduleDAGMI::checkSchedLimit() {
82161cfbce3SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
8220b57cec5SDimitry Andric   if (NumInstrsScheduled == MISchedCutoff && MISchedCutoff != ~0U) {
8230b57cec5SDimitry Andric     CurrentTop = CurrentBottom;
8240b57cec5SDimitry Andric     return false;
8250b57cec5SDimitry Andric   }
8260b57cec5SDimitry Andric   ++NumInstrsScheduled;
8270b57cec5SDimitry Andric #endif
8280b57cec5SDimitry Andric   return true;
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric /// Per-region scheduling driver, called back from
8325f757f3fSDimitry Andric /// PostMachineScheduler::runOnMachineFunction. This is a simplified driver
8335f757f3fSDimitry Andric /// that does not consider liveness or register pressure. It is useful for
8345f757f3fSDimitry Andric /// PostRA scheduling and potentially other custom schedulers.
8350b57cec5SDimitry Andric void ScheduleDAGMI::schedule() {
8360b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "ScheduleDAGMI::schedule starting\n");
8370b57cec5SDimitry Andric   LLVM_DEBUG(SchedImpl->dumpPolicy());
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric   // Build the DAG.
8400b57cec5SDimitry Andric   buildSchedGraph(AA);
8410b57cec5SDimitry Andric 
84206c3fb27SDimitry Andric   postProcessDAG();
8430b57cec5SDimitry Andric 
8440b57cec5SDimitry Andric   SmallVector<SUnit*, 8> TopRoots, BotRoots;
8450b57cec5SDimitry Andric   findRootsAndBiasEdges(TopRoots, BotRoots);
8460b57cec5SDimitry Andric 
8470b57cec5SDimitry Andric   LLVM_DEBUG(dump());
8480b57cec5SDimitry Andric   if (PrintDAGs) dump();
8490b57cec5SDimitry Andric   if (ViewMISchedDAGs) viewGraph();
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric   // Initialize the strategy before modifying the DAG.
8520b57cec5SDimitry Andric   // This may initialize a DFSResult to be used for queue priority.
8530b57cec5SDimitry Andric   SchedImpl->initialize(this);
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric   // Initialize ready queues now that the DAG and priority data are finalized.
8560b57cec5SDimitry Andric   initQueues(TopRoots, BotRoots);
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric   bool IsTopNode = false;
8590b57cec5SDimitry Andric   while (true) {
8600b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "** ScheduleDAGMI::schedule picking next node\n");
8610b57cec5SDimitry Andric     SUnit *SU = SchedImpl->pickNode(IsTopNode);
8620b57cec5SDimitry Andric     if (!SU) break;
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric     assert(!SU->isScheduled && "Node already scheduled");
8650b57cec5SDimitry Andric     if (!checkSchedLimit())
8660b57cec5SDimitry Andric       break;
8670b57cec5SDimitry Andric 
8680b57cec5SDimitry Andric     MachineInstr *MI = SU->getInstr();
8690b57cec5SDimitry Andric     if (IsTopNode) {
8700b57cec5SDimitry Andric       assert(SU->isTopReady() && "node still has unscheduled dependencies");
8710b57cec5SDimitry Andric       if (&*CurrentTop == MI)
8720b57cec5SDimitry Andric         CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom);
8730b57cec5SDimitry Andric       else
8740b57cec5SDimitry Andric         moveInstruction(MI, CurrentTop);
8750b57cec5SDimitry Andric     } else {
8760b57cec5SDimitry Andric       assert(SU->isBottomReady() && "node still has unscheduled dependencies");
8770b57cec5SDimitry Andric       MachineBasicBlock::iterator priorII =
8780b57cec5SDimitry Andric         priorNonDebug(CurrentBottom, CurrentTop);
8790b57cec5SDimitry Andric       if (&*priorII == MI)
8800b57cec5SDimitry Andric         CurrentBottom = priorII;
8810b57cec5SDimitry Andric       else {
8820b57cec5SDimitry Andric         if (&*CurrentTop == MI)
8830b57cec5SDimitry Andric           CurrentTop = nextIfDebug(++CurrentTop, priorII);
8840b57cec5SDimitry Andric         moveInstruction(MI, CurrentBottom);
8850b57cec5SDimitry Andric         CurrentBottom = MI;
8860b57cec5SDimitry Andric       }
8870b57cec5SDimitry Andric     }
8880b57cec5SDimitry Andric     // Notify the scheduling strategy before updating the DAG.
8890b57cec5SDimitry Andric     // This sets the scheduled node's ReadyCycle to CurrCycle. When updateQueues
8900b57cec5SDimitry Andric     // runs, it can then use the accurate ReadyCycle time to determine whether
8910b57cec5SDimitry Andric     // newly released nodes can move to the readyQ.
8920b57cec5SDimitry Andric     SchedImpl->schedNode(SU, IsTopNode);
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric     updateQueues(SU, IsTopNode);
8950b57cec5SDimitry Andric   }
8960b57cec5SDimitry Andric   assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   placeDebugValues();
8990b57cec5SDimitry Andric 
9000b57cec5SDimitry Andric   LLVM_DEBUG({
9010b57cec5SDimitry Andric     dbgs() << "*** Final schedule for "
9020b57cec5SDimitry Andric            << printMBBReference(*begin()->getParent()) << " ***\n";
9030b57cec5SDimitry Andric     dumpSchedule();
9040b57cec5SDimitry Andric     dbgs() << '\n';
9050b57cec5SDimitry Andric   });
9060b57cec5SDimitry Andric }
9070b57cec5SDimitry Andric 
9080b57cec5SDimitry Andric /// Apply each ScheduleDAGMutation step in order.
90906c3fb27SDimitry Andric void ScheduleDAGMI::postProcessDAG() {
9100b57cec5SDimitry Andric   for (auto &m : Mutations)
9110b57cec5SDimitry Andric     m->apply(this);
9120b57cec5SDimitry Andric }
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric void ScheduleDAGMI::
9150b57cec5SDimitry Andric findRootsAndBiasEdges(SmallVectorImpl<SUnit*> &TopRoots,
9160b57cec5SDimitry Andric                       SmallVectorImpl<SUnit*> &BotRoots) {
9170b57cec5SDimitry Andric   for (SUnit &SU : SUnits) {
9180b57cec5SDimitry Andric     assert(!SU.isBoundaryNode() && "Boundary node should not be in SUnits");
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric     // Order predecessors so DFSResult follows the critical path.
9210b57cec5SDimitry Andric     SU.biasCriticalPath();
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric     // A SUnit is ready to top schedule if it has no predecessors.
9240b57cec5SDimitry Andric     if (!SU.NumPredsLeft)
9250b57cec5SDimitry Andric       TopRoots.push_back(&SU);
9260b57cec5SDimitry Andric     // A SUnit is ready to bottom schedule if it has no successors.
9270b57cec5SDimitry Andric     if (!SU.NumSuccsLeft)
9280b57cec5SDimitry Andric       BotRoots.push_back(&SU);
9290b57cec5SDimitry Andric   }
9300b57cec5SDimitry Andric   ExitSU.biasCriticalPath();
9310b57cec5SDimitry Andric }
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric /// Identify DAG roots and setup scheduler queues.
9340b57cec5SDimitry Andric void ScheduleDAGMI::initQueues(ArrayRef<SUnit*> TopRoots,
9350b57cec5SDimitry Andric                                ArrayRef<SUnit*> BotRoots) {
9360b57cec5SDimitry Andric   NextClusterSucc = nullptr;
9370b57cec5SDimitry Andric   NextClusterPred = nullptr;
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric   // Release all DAG roots for scheduling, not including EntrySU/ExitSU.
9400b57cec5SDimitry Andric   //
9410b57cec5SDimitry Andric   // Nodes with unreleased weak edges can still be roots.
9420b57cec5SDimitry Andric   // Release top roots in forward order.
9430b57cec5SDimitry Andric   for (SUnit *SU : TopRoots)
9440b57cec5SDimitry Andric     SchedImpl->releaseTopNode(SU);
9450b57cec5SDimitry Andric 
9460b57cec5SDimitry Andric   // Release bottom roots in reverse order so the higher priority nodes appear
9470b57cec5SDimitry Andric   // first. This is more natural and slightly more efficient.
9480b57cec5SDimitry Andric   for (SmallVectorImpl<SUnit*>::const_reverse_iterator
9490b57cec5SDimitry Andric          I = BotRoots.rbegin(), E = BotRoots.rend(); I != E; ++I) {
9500b57cec5SDimitry Andric     SchedImpl->releaseBottomNode(*I);
9510b57cec5SDimitry Andric   }
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric   releaseSuccessors(&EntrySU);
9540b57cec5SDimitry Andric   releasePredecessors(&ExitSU);
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric   SchedImpl->registerRoots();
9570b57cec5SDimitry Andric 
9580b57cec5SDimitry Andric   // Advance past initial DebugValues.
9590b57cec5SDimitry Andric   CurrentTop = nextIfDebug(RegionBegin, RegionEnd);
9600b57cec5SDimitry Andric   CurrentBottom = RegionEnd;
9610b57cec5SDimitry Andric }
9620b57cec5SDimitry Andric 
9630b57cec5SDimitry Andric /// Update scheduler queues after scheduling an instruction.
9640b57cec5SDimitry Andric void ScheduleDAGMI::updateQueues(SUnit *SU, bool IsTopNode) {
9650b57cec5SDimitry Andric   // Release dependent instructions for scheduling.
9660b57cec5SDimitry Andric   if (IsTopNode)
9670b57cec5SDimitry Andric     releaseSuccessors(SU);
9680b57cec5SDimitry Andric   else
9690b57cec5SDimitry Andric     releasePredecessors(SU);
9700b57cec5SDimitry Andric 
9710b57cec5SDimitry Andric   SU->isScheduled = true;
9720b57cec5SDimitry Andric }
9730b57cec5SDimitry Andric 
9740b57cec5SDimitry Andric /// Reinsert any remaining debug_values, just like the PostRA scheduler.
9750b57cec5SDimitry Andric void ScheduleDAGMI::placeDebugValues() {
9760b57cec5SDimitry Andric   // If first instruction was a DBG_VALUE then put it back.
9770b57cec5SDimitry Andric   if (FirstDbgValue) {
9780b57cec5SDimitry Andric     BB->splice(RegionBegin, BB, FirstDbgValue);
9790b57cec5SDimitry Andric     RegionBegin = FirstDbgValue;
9800b57cec5SDimitry Andric   }
9810b57cec5SDimitry Andric 
9820b57cec5SDimitry Andric   for (std::vector<std::pair<MachineInstr *, MachineInstr *>>::iterator
9830b57cec5SDimitry Andric          DI = DbgValues.end(), DE = DbgValues.begin(); DI != DE; --DI) {
9840b57cec5SDimitry Andric     std::pair<MachineInstr *, MachineInstr *> P = *std::prev(DI);
9850b57cec5SDimitry Andric     MachineInstr *DbgValue = P.first;
9860b57cec5SDimitry Andric     MachineBasicBlock::iterator OrigPrevMI = P.second;
9870b57cec5SDimitry Andric     if (&*RegionBegin == DbgValue)
9880b57cec5SDimitry Andric       ++RegionBegin;
98981ad6265SDimitry Andric     BB->splice(std::next(OrigPrevMI), BB, DbgValue);
99081ad6265SDimitry Andric     if (RegionEnd != BB->end() && OrigPrevMI == &*RegionEnd)
9910b57cec5SDimitry Andric       RegionEnd = DbgValue;
9920b57cec5SDimitry Andric   }
9930b57cec5SDimitry Andric }
9940b57cec5SDimitry Andric 
9950b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
99606c3fb27SDimitry Andric static const char *scheduleTableLegend = "  i: issue\n  x: resource booked";
99706c3fb27SDimitry Andric 
99806c3fb27SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceTopDown() const {
99906c3fb27SDimitry Andric   // Bail off when there is no schedule model to query.
100006c3fb27SDimitry Andric   if (!SchedModel.hasInstrSchedModel())
100106c3fb27SDimitry Andric     return;
100206c3fb27SDimitry Andric 
100306c3fb27SDimitry Andric   //  Nothing to show if there is no or just one instruction.
100406c3fb27SDimitry Andric   if (BB->size() < 2)
100506c3fb27SDimitry Andric     return;
100606c3fb27SDimitry Andric 
100706c3fb27SDimitry Andric   dbgs() << " * Schedule table (TopDown):\n";
100806c3fb27SDimitry Andric   dbgs() << scheduleTableLegend << "\n";
100906c3fb27SDimitry Andric   const unsigned FirstCycle = getSUnit(&*(std::begin(*this)))->TopReadyCycle;
101006c3fb27SDimitry Andric   unsigned LastCycle = getSUnit(&*(std::prev(std::end(*this))))->TopReadyCycle;
101106c3fb27SDimitry Andric   for (MachineInstr &MI : *this) {
101206c3fb27SDimitry Andric     SUnit *SU = getSUnit(&MI);
101306c3fb27SDimitry Andric     if (!SU)
101406c3fb27SDimitry Andric       continue;
101506c3fb27SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
101606c3fb27SDimitry Andric     for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC),
101706c3fb27SDimitry Andric                                        PE = SchedModel.getWriteProcResEnd(SC);
101806c3fb27SDimitry Andric          PI != PE; ++PI) {
10195f757f3fSDimitry Andric       if (SU->TopReadyCycle + PI->ReleaseAtCycle - 1 > LastCycle)
10205f757f3fSDimitry Andric         LastCycle = SU->TopReadyCycle + PI->ReleaseAtCycle - 1;
102106c3fb27SDimitry Andric     }
102206c3fb27SDimitry Andric   }
102306c3fb27SDimitry Andric   // Print the header with the cycles
102406c3fb27SDimitry Andric   dbgs() << llvm::left_justify("Cycle", HeaderColWidth);
102506c3fb27SDimitry Andric   for (unsigned C = FirstCycle; C <= LastCycle; ++C)
102606c3fb27SDimitry Andric     dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth);
102706c3fb27SDimitry Andric   dbgs() << "|\n";
102806c3fb27SDimitry Andric 
102906c3fb27SDimitry Andric   for (MachineInstr &MI : *this) {
103006c3fb27SDimitry Andric     SUnit *SU = getSUnit(&MI);
103106c3fb27SDimitry Andric     if (!SU) {
103206c3fb27SDimitry Andric       dbgs() << "Missing SUnit\n";
103306c3fb27SDimitry Andric       continue;
103406c3fb27SDimitry Andric     }
103506c3fb27SDimitry Andric     std::string NodeName("SU(");
103606c3fb27SDimitry Andric     NodeName += std::to_string(SU->NodeNum) + ")";
103706c3fb27SDimitry Andric     dbgs() << llvm::left_justify(NodeName, HeaderColWidth);
103806c3fb27SDimitry Andric     unsigned C = FirstCycle;
103906c3fb27SDimitry Andric     for (; C <= LastCycle; ++C) {
104006c3fb27SDimitry Andric       if (C == SU->TopReadyCycle)
104106c3fb27SDimitry Andric         dbgs() << llvm::left_justify("| i", ColWidth);
104206c3fb27SDimitry Andric       else
104306c3fb27SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
104406c3fb27SDimitry Andric     }
104506c3fb27SDimitry Andric     dbgs() << "|\n";
104606c3fb27SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
104706c3fb27SDimitry Andric 
104806c3fb27SDimitry Andric     SmallVector<MCWriteProcResEntry, 4> ResourcesIt(
104906c3fb27SDimitry Andric         make_range(SchedModel.getWriteProcResBegin(SC),
105006c3fb27SDimitry Andric                    SchedModel.getWriteProcResEnd(SC)));
105106c3fb27SDimitry Andric 
105206c3fb27SDimitry Andric     if (MISchedSortResourcesInTrace)
105306c3fb27SDimitry Andric       llvm::stable_sort(ResourcesIt,
105406c3fb27SDimitry Andric                         [](const MCWriteProcResEntry &LHS,
105506c3fb27SDimitry Andric                            const MCWriteProcResEntry &RHS) -> bool {
10565f757f3fSDimitry Andric                           return LHS.AcquireAtCycle < RHS.AcquireAtCycle ||
10575f757f3fSDimitry Andric                                  (LHS.AcquireAtCycle == RHS.AcquireAtCycle &&
10585f757f3fSDimitry Andric                                   LHS.ReleaseAtCycle < RHS.ReleaseAtCycle);
105906c3fb27SDimitry Andric                         });
106006c3fb27SDimitry Andric     for (const MCWriteProcResEntry &PI : ResourcesIt) {
106106c3fb27SDimitry Andric       C = FirstCycle;
106206c3fb27SDimitry Andric       const std::string ResName =
106306c3fb27SDimitry Andric           SchedModel.getResourceName(PI.ProcResourceIdx);
106406c3fb27SDimitry Andric       dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth);
10655f757f3fSDimitry Andric       for (; C < SU->TopReadyCycle + PI.AcquireAtCycle; ++C) {
106606c3fb27SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
106706c3fb27SDimitry Andric       }
10685f757f3fSDimitry Andric       for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E;
10695f757f3fSDimitry Andric            ++I, ++C)
107006c3fb27SDimitry Andric         dbgs() << llvm::left_justify("| x", ColWidth);
107106c3fb27SDimitry Andric       while (C++ <= LastCycle)
107206c3fb27SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
107306c3fb27SDimitry Andric       // Place end char
107406c3fb27SDimitry Andric       dbgs() << "| \n";
107506c3fb27SDimitry Andric     }
107606c3fb27SDimitry Andric   }
107706c3fb27SDimitry Andric }
107806c3fb27SDimitry Andric 
107906c3fb27SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceBottomUp() const {
108006c3fb27SDimitry Andric   // Bail off when there is no schedule model to query.
108106c3fb27SDimitry Andric   if (!SchedModel.hasInstrSchedModel())
108206c3fb27SDimitry Andric     return;
108306c3fb27SDimitry Andric 
108406c3fb27SDimitry Andric   //  Nothing to show if there is no or just one instruction.
108506c3fb27SDimitry Andric   if (BB->size() < 2)
108606c3fb27SDimitry Andric     return;
108706c3fb27SDimitry Andric 
108806c3fb27SDimitry Andric   dbgs() << " * Schedule table (BottomUp):\n";
108906c3fb27SDimitry Andric   dbgs() << scheduleTableLegend << "\n";
109006c3fb27SDimitry Andric 
109106c3fb27SDimitry Andric   const int FirstCycle = getSUnit(&*(std::begin(*this)))->BotReadyCycle;
109206c3fb27SDimitry Andric   int LastCycle = getSUnit(&*(std::prev(std::end(*this))))->BotReadyCycle;
109306c3fb27SDimitry Andric   for (MachineInstr &MI : *this) {
109406c3fb27SDimitry Andric     SUnit *SU = getSUnit(&MI);
109506c3fb27SDimitry Andric     if (!SU)
109606c3fb27SDimitry Andric       continue;
109706c3fb27SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
109806c3fb27SDimitry Andric     for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC),
109906c3fb27SDimitry Andric                                        PE = SchedModel.getWriteProcResEnd(SC);
110006c3fb27SDimitry Andric          PI != PE; ++PI) {
11015f757f3fSDimitry Andric       if ((int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1 < LastCycle)
11025f757f3fSDimitry Andric         LastCycle = (int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1;
110306c3fb27SDimitry Andric     }
110406c3fb27SDimitry Andric   }
110506c3fb27SDimitry Andric   // Print the header with the cycles
110606c3fb27SDimitry Andric   dbgs() << llvm::left_justify("Cycle", HeaderColWidth);
110706c3fb27SDimitry Andric   for (int C = FirstCycle; C >= LastCycle; --C)
110806c3fb27SDimitry Andric     dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth);
110906c3fb27SDimitry Andric   dbgs() << "|\n";
111006c3fb27SDimitry Andric 
111106c3fb27SDimitry Andric   for (MachineInstr &MI : *this) {
111206c3fb27SDimitry Andric     SUnit *SU = getSUnit(&MI);
111306c3fb27SDimitry Andric     if (!SU) {
111406c3fb27SDimitry Andric       dbgs() << "Missing SUnit\n";
111506c3fb27SDimitry Andric       continue;
111606c3fb27SDimitry Andric     }
111706c3fb27SDimitry Andric     std::string NodeName("SU(");
111806c3fb27SDimitry Andric     NodeName += std::to_string(SU->NodeNum) + ")";
111906c3fb27SDimitry Andric     dbgs() << llvm::left_justify(NodeName, HeaderColWidth);
112006c3fb27SDimitry Andric     int C = FirstCycle;
112106c3fb27SDimitry Andric     for (; C >= LastCycle; --C) {
112206c3fb27SDimitry Andric       if (C == (int)SU->BotReadyCycle)
112306c3fb27SDimitry Andric         dbgs() << llvm::left_justify("| i", ColWidth);
112406c3fb27SDimitry Andric       else
112506c3fb27SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
112606c3fb27SDimitry Andric     }
112706c3fb27SDimitry Andric     dbgs() << "|\n";
112806c3fb27SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
112906c3fb27SDimitry Andric     SmallVector<MCWriteProcResEntry, 4> ResourcesIt(
113006c3fb27SDimitry Andric         make_range(SchedModel.getWriteProcResBegin(SC),
113106c3fb27SDimitry Andric                    SchedModel.getWriteProcResEnd(SC)));
113206c3fb27SDimitry Andric 
113306c3fb27SDimitry Andric     if (MISchedSortResourcesInTrace)
113406c3fb27SDimitry Andric       llvm::stable_sort(ResourcesIt,
113506c3fb27SDimitry Andric                         [](const MCWriteProcResEntry &LHS,
113606c3fb27SDimitry Andric                            const MCWriteProcResEntry &RHS) -> bool {
11375f757f3fSDimitry Andric                           return LHS.AcquireAtCycle < RHS.AcquireAtCycle ||
11385f757f3fSDimitry Andric                                  (LHS.AcquireAtCycle == RHS.AcquireAtCycle &&
11395f757f3fSDimitry Andric                                   LHS.ReleaseAtCycle < RHS.ReleaseAtCycle);
114006c3fb27SDimitry Andric                         });
114106c3fb27SDimitry Andric     for (const MCWriteProcResEntry &PI : ResourcesIt) {
114206c3fb27SDimitry Andric       C = FirstCycle;
114306c3fb27SDimitry Andric       const std::string ResName =
114406c3fb27SDimitry Andric           SchedModel.getResourceName(PI.ProcResourceIdx);
114506c3fb27SDimitry Andric       dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth);
11465f757f3fSDimitry Andric       for (; C > ((int)SU->BotReadyCycle - (int)PI.AcquireAtCycle); --C) {
114706c3fb27SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
114806c3fb27SDimitry Andric       }
11495f757f3fSDimitry Andric       for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E;
11505f757f3fSDimitry Andric            ++I, --C)
115106c3fb27SDimitry Andric         dbgs() << llvm::left_justify("| x", ColWidth);
115206c3fb27SDimitry Andric       while (C-- >= LastCycle)
115306c3fb27SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
115406c3fb27SDimitry Andric       // Place end char
115506c3fb27SDimitry Andric       dbgs() << "| \n";
115606c3fb27SDimitry Andric     }
115706c3fb27SDimitry Andric   }
115806c3fb27SDimitry Andric }
115906c3fb27SDimitry Andric #endif
116006c3fb27SDimitry Andric 
116106c3fb27SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
11620b57cec5SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpSchedule() const {
116306c3fb27SDimitry Andric   if (MISchedDumpScheduleTrace) {
1164*0fca6ea1SDimitry Andric     if (DumpDir == DumpDirection::TopDown)
116506c3fb27SDimitry Andric       dumpScheduleTraceTopDown();
1166*0fca6ea1SDimitry Andric     else if (DumpDir == DumpDirection::BottomUp)
116706c3fb27SDimitry Andric       dumpScheduleTraceBottomUp();
1168*0fca6ea1SDimitry Andric     else if (DumpDir == DumpDirection::Bidirectional) {
116906c3fb27SDimitry Andric       dbgs() << "* Schedule table (Bidirectional): not implemented\n";
1170*0fca6ea1SDimitry Andric     } else {
1171*0fca6ea1SDimitry Andric       dbgs() << "* Schedule table: DumpDirection not set.\n";
117206c3fb27SDimitry Andric     }
117306c3fb27SDimitry Andric   }
117406c3fb27SDimitry Andric 
1175fe6060f1SDimitry Andric   for (MachineInstr &MI : *this) {
1176fe6060f1SDimitry Andric     if (SUnit *SU = getSUnit(&MI))
11770b57cec5SDimitry Andric       dumpNode(*SU);
11780b57cec5SDimitry Andric     else
11790b57cec5SDimitry Andric       dbgs() << "Missing SUnit\n";
11800b57cec5SDimitry Andric   }
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric #endif
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11850b57cec5SDimitry Andric // ScheduleDAGMILive - Base class for MachineInstr scheduling with LiveIntervals
11860b57cec5SDimitry Andric // preservation.
11870b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11880b57cec5SDimitry Andric 
11890b57cec5SDimitry Andric ScheduleDAGMILive::~ScheduleDAGMILive() {
11900b57cec5SDimitry Andric   delete DFSResult;
11910b57cec5SDimitry Andric }
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric void ScheduleDAGMILive::collectVRegUses(SUnit &SU) {
11940b57cec5SDimitry Andric   const MachineInstr &MI = *SU.getInstr();
11950b57cec5SDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
11960b57cec5SDimitry Andric     if (!MO.isReg())
11970b57cec5SDimitry Andric       continue;
11980b57cec5SDimitry Andric     if (!MO.readsReg())
11990b57cec5SDimitry Andric       continue;
12000b57cec5SDimitry Andric     if (TrackLaneMasks && !MO.isUse())
12010b57cec5SDimitry Andric       continue;
12020b57cec5SDimitry Andric 
12038bcb0991SDimitry Andric     Register Reg = MO.getReg();
1204bdd1243dSDimitry Andric     if (!Reg.isVirtual())
12050b57cec5SDimitry Andric       continue;
12060b57cec5SDimitry Andric 
12070b57cec5SDimitry Andric     // Ignore re-defs.
12080b57cec5SDimitry Andric     if (TrackLaneMasks) {
12090b57cec5SDimitry Andric       bool FoundDef = false;
121006c3fb27SDimitry Andric       for (const MachineOperand &MO2 : MI.all_defs()) {
121106c3fb27SDimitry Andric         if (MO2.getReg() == Reg && !MO2.isDead()) {
12120b57cec5SDimitry Andric           FoundDef = true;
12130b57cec5SDimitry Andric           break;
12140b57cec5SDimitry Andric         }
12150b57cec5SDimitry Andric       }
12160b57cec5SDimitry Andric       if (FoundDef)
12170b57cec5SDimitry Andric         continue;
12180b57cec5SDimitry Andric     }
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric     // Record this local VReg use.
12210b57cec5SDimitry Andric     VReg2SUnitMultiMap::iterator UI = VRegUses.find(Reg);
12220b57cec5SDimitry Andric     for (; UI != VRegUses.end(); ++UI) {
12230b57cec5SDimitry Andric       if (UI->SU == &SU)
12240b57cec5SDimitry Andric         break;
12250b57cec5SDimitry Andric     }
12260b57cec5SDimitry Andric     if (UI == VRegUses.end())
12270b57cec5SDimitry Andric       VRegUses.insert(VReg2SUnit(Reg, LaneBitmask::getNone(), &SU));
12280b57cec5SDimitry Andric   }
12290b57cec5SDimitry Andric }
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric /// enterRegion - Called back from MachineScheduler::runOnMachineFunction after
12320b57cec5SDimitry Andric /// crossing a scheduling boundary. [begin, end) includes all instructions in
12330b57cec5SDimitry Andric /// the region, including the boundary itself and single-instruction regions
12340b57cec5SDimitry Andric /// that don't get scheduled.
12350b57cec5SDimitry Andric void ScheduleDAGMILive::enterRegion(MachineBasicBlock *bb,
12360b57cec5SDimitry Andric                                 MachineBasicBlock::iterator begin,
12370b57cec5SDimitry Andric                                 MachineBasicBlock::iterator end,
12380b57cec5SDimitry Andric                                 unsigned regioninstrs)
12390b57cec5SDimitry Andric {
12400b57cec5SDimitry Andric   // ScheduleDAGMI initializes SchedImpl's per-region policy.
12410b57cec5SDimitry Andric   ScheduleDAGMI::enterRegion(bb, begin, end, regioninstrs);
12420b57cec5SDimitry Andric 
12430b57cec5SDimitry Andric   // For convenience remember the end of the liveness region.
12440b57cec5SDimitry Andric   LiveRegionEnd = (RegionEnd == bb->end()) ? RegionEnd : std::next(RegionEnd);
12450b57cec5SDimitry Andric 
12460b57cec5SDimitry Andric   SUPressureDiffs.clear();
12470b57cec5SDimitry Andric 
12480b57cec5SDimitry Andric   ShouldTrackPressure = SchedImpl->shouldTrackPressure();
12490b57cec5SDimitry Andric   ShouldTrackLaneMasks = SchedImpl->shouldTrackLaneMasks();
12500b57cec5SDimitry Andric 
12510b57cec5SDimitry Andric   assert((!ShouldTrackLaneMasks || ShouldTrackPressure) &&
12520b57cec5SDimitry Andric          "ShouldTrackLaneMasks requires ShouldTrackPressure");
12530b57cec5SDimitry Andric }
12540b57cec5SDimitry Andric 
12558bcb0991SDimitry Andric // Setup the register pressure trackers for the top scheduled and bottom
12560b57cec5SDimitry Andric // scheduled regions.
12570b57cec5SDimitry Andric void ScheduleDAGMILive::initRegPressure() {
12580b57cec5SDimitry Andric   VRegUses.clear();
12590b57cec5SDimitry Andric   VRegUses.setUniverse(MRI.getNumVirtRegs());
12600b57cec5SDimitry Andric   for (SUnit &SU : SUnits)
12610b57cec5SDimitry Andric     collectVRegUses(SU);
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric   TopRPTracker.init(&MF, RegClassInfo, LIS, BB, RegionBegin,
12640b57cec5SDimitry Andric                     ShouldTrackLaneMasks, false);
12650b57cec5SDimitry Andric   BotRPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd,
12660b57cec5SDimitry Andric                     ShouldTrackLaneMasks, false);
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric   // Close the RPTracker to finalize live ins.
12690b57cec5SDimitry Andric   RPTracker.closeRegion();
12700b57cec5SDimitry Andric 
12710b57cec5SDimitry Andric   LLVM_DEBUG(RPTracker.dump());
12720b57cec5SDimitry Andric 
12730b57cec5SDimitry Andric   // Initialize the live ins and live outs.
12740b57cec5SDimitry Andric   TopRPTracker.addLiveRegs(RPTracker.getPressure().LiveInRegs);
12750b57cec5SDimitry Andric   BotRPTracker.addLiveRegs(RPTracker.getPressure().LiveOutRegs);
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric   // Close one end of the tracker so we can call
12780b57cec5SDimitry Andric   // getMaxUpward/DownwardPressureDelta before advancing across any
12790b57cec5SDimitry Andric   // instructions. This converts currently live regs into live ins/outs.
12800b57cec5SDimitry Andric   TopRPTracker.closeTop();
12810b57cec5SDimitry Andric   BotRPTracker.closeBottom();
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric   BotRPTracker.initLiveThru(RPTracker);
12840b57cec5SDimitry Andric   if (!BotRPTracker.getLiveThru().empty()) {
12850b57cec5SDimitry Andric     TopRPTracker.initLiveThru(BotRPTracker.getLiveThru());
12860b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Live Thru: ";
12870b57cec5SDimitry Andric                dumpRegSetPressure(BotRPTracker.getLiveThru(), TRI));
12880b57cec5SDimitry Andric   };
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric   // For each live out vreg reduce the pressure change associated with other
12910b57cec5SDimitry Andric   // uses of the same vreg below the live-out reaching def.
12920b57cec5SDimitry Andric   updatePressureDiffs(RPTracker.getPressure().LiveOutRegs);
12930b57cec5SDimitry Andric 
12940b57cec5SDimitry Andric   // Account for liveness generated by the region boundary.
12950b57cec5SDimitry Andric   if (LiveRegionEnd != RegionEnd) {
12960b57cec5SDimitry Andric     SmallVector<RegisterMaskPair, 8> LiveUses;
12970b57cec5SDimitry Andric     BotRPTracker.recede(&LiveUses);
12980b57cec5SDimitry Andric     updatePressureDiffs(LiveUses);
12990b57cec5SDimitry Andric   }
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Top Pressure:\n";
13020b57cec5SDimitry Andric              dumpRegSetPressure(TopRPTracker.getRegSetPressureAtPos(), TRI);
13030b57cec5SDimitry Andric              dbgs() << "Bottom Pressure:\n";
13040b57cec5SDimitry Andric              dumpRegSetPressure(BotRPTracker.getRegSetPressureAtPos(), TRI););
13050b57cec5SDimitry Andric 
13060b57cec5SDimitry Andric   assert((BotRPTracker.getPos() == RegionEnd ||
13070b57cec5SDimitry Andric           (RegionEnd->isDebugInstr() &&
13080b57cec5SDimitry Andric            BotRPTracker.getPos() == priorNonDebug(RegionEnd, RegionBegin))) &&
13090b57cec5SDimitry Andric          "Can't find the region bottom");
13100b57cec5SDimitry Andric 
13110b57cec5SDimitry Andric   // Cache the list of excess pressure sets in this region. This will also track
13120b57cec5SDimitry Andric   // the max pressure in the scheduled code for these sets.
13130b57cec5SDimitry Andric   RegionCriticalPSets.clear();
13140b57cec5SDimitry Andric   const std::vector<unsigned> &RegionPressure =
13150b57cec5SDimitry Andric     RPTracker.getPressure().MaxSetPressure;
13160b57cec5SDimitry Andric   for (unsigned i = 0, e = RegionPressure.size(); i < e; ++i) {
13170b57cec5SDimitry Andric     unsigned Limit = RegClassInfo->getRegPressureSetLimit(i);
13180b57cec5SDimitry Andric     if (RegionPressure[i] > Limit) {
13190b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << TRI->getRegPressureSetName(i) << " Limit " << Limit
13200b57cec5SDimitry Andric                         << " Actual " << RegionPressure[i] << "\n");
13210b57cec5SDimitry Andric       RegionCriticalPSets.push_back(PressureChange(i));
13220b57cec5SDimitry Andric     }
13230b57cec5SDimitry Andric   }
13240b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Excess PSets: ";
13250b57cec5SDimitry Andric              for (const PressureChange &RCPS
13260b57cec5SDimitry Andric                   : RegionCriticalPSets) dbgs()
13270b57cec5SDimitry Andric              << TRI->getRegPressureSetName(RCPS.getPSet()) << " ";
13280b57cec5SDimitry Andric              dbgs() << "\n");
13290b57cec5SDimitry Andric }
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric void ScheduleDAGMILive::
13320b57cec5SDimitry Andric updateScheduledPressure(const SUnit *SU,
13330b57cec5SDimitry Andric                         const std::vector<unsigned> &NewMaxPressure) {
13340b57cec5SDimitry Andric   const PressureDiff &PDiff = getPressureDiff(SU);
13350b57cec5SDimitry Andric   unsigned CritIdx = 0, CritEnd = RegionCriticalPSets.size();
13360b57cec5SDimitry Andric   for (const PressureChange &PC : PDiff) {
13370b57cec5SDimitry Andric     if (!PC.isValid())
13380b57cec5SDimitry Andric       break;
13390b57cec5SDimitry Andric     unsigned ID = PC.getPSet();
13400b57cec5SDimitry Andric     while (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() < ID)
13410b57cec5SDimitry Andric       ++CritIdx;
13420b57cec5SDimitry Andric     if (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() == ID) {
13430b57cec5SDimitry Andric       if ((int)NewMaxPressure[ID] > RegionCriticalPSets[CritIdx].getUnitInc()
13440b57cec5SDimitry Andric           && NewMaxPressure[ID] <= (unsigned)std::numeric_limits<int16_t>::max())
13450b57cec5SDimitry Andric         RegionCriticalPSets[CritIdx].setUnitInc(NewMaxPressure[ID]);
13460b57cec5SDimitry Andric     }
13470b57cec5SDimitry Andric     unsigned Limit = RegClassInfo->getRegPressureSetLimit(ID);
13480b57cec5SDimitry Andric     if (NewMaxPressure[ID] >= Limit - 2) {
13490b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "  " << TRI->getRegPressureSetName(ID) << ": "
13500b57cec5SDimitry Andric                         << NewMaxPressure[ID]
13510b57cec5SDimitry Andric                         << ((NewMaxPressure[ID] > Limit) ? " > " : " <= ")
13520b57cec5SDimitry Andric                         << Limit << "(+ " << BotRPTracker.getLiveThru()[ID]
13530b57cec5SDimitry Andric                         << " livethru)\n");
13540b57cec5SDimitry Andric     }
13550b57cec5SDimitry Andric   }
13560b57cec5SDimitry Andric }
13570b57cec5SDimitry Andric 
13580b57cec5SDimitry Andric /// Update the PressureDiff array for liveness after scheduling this
13590b57cec5SDimitry Andric /// instruction.
13600b57cec5SDimitry Andric void ScheduleDAGMILive::updatePressureDiffs(
13610b57cec5SDimitry Andric     ArrayRef<RegisterMaskPair> LiveUses) {
13620b57cec5SDimitry Andric   for (const RegisterMaskPair &P : LiveUses) {
1363e8d8bef9SDimitry Andric     Register Reg = P.RegUnit;
13640b57cec5SDimitry Andric     /// FIXME: Currently assuming single-use physregs.
1365bdd1243dSDimitry Andric     if (!Reg.isVirtual())
13660b57cec5SDimitry Andric       continue;
13670b57cec5SDimitry Andric 
13680b57cec5SDimitry Andric     if (ShouldTrackLaneMasks) {
13690b57cec5SDimitry Andric       // If the register has just become live then other uses won't change
13700b57cec5SDimitry Andric       // this fact anymore => decrement pressure.
13710b57cec5SDimitry Andric       // If the register has just become dead then other uses make it come
13720b57cec5SDimitry Andric       // back to life => increment pressure.
13730b57cec5SDimitry Andric       bool Decrement = P.LaneMask.any();
13740b57cec5SDimitry Andric 
13750b57cec5SDimitry Andric       for (const VReg2SUnit &V2SU
13760b57cec5SDimitry Andric            : make_range(VRegUses.find(Reg), VRegUses.end())) {
13770b57cec5SDimitry Andric         SUnit &SU = *V2SU.SU;
13780b57cec5SDimitry Andric         if (SU.isScheduled || &SU == &ExitSU)
13790b57cec5SDimitry Andric           continue;
13800b57cec5SDimitry Andric 
13810b57cec5SDimitry Andric         PressureDiff &PDiff = getPressureDiff(&SU);
13820b57cec5SDimitry Andric         PDiff.addPressureChange(Reg, Decrement, &MRI);
13830b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "  UpdateRegP: SU(" << SU.NodeNum << ") "
13840b57cec5SDimitry Andric                           << printReg(Reg, TRI) << ':'
13850b57cec5SDimitry Andric                           << PrintLaneMask(P.LaneMask) << ' ' << *SU.getInstr();
13860b57cec5SDimitry Andric                    dbgs() << "              to "; PDiff.dump(*TRI););
13870b57cec5SDimitry Andric       }
13880b57cec5SDimitry Andric     } else {
13890b57cec5SDimitry Andric       assert(P.LaneMask.any());
13900b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "  LiveReg: " << printVRegOrUnit(Reg, TRI) << "\n");
13910b57cec5SDimitry Andric       // This may be called before CurrentBottom has been initialized. However,
13920b57cec5SDimitry Andric       // BotRPTracker must have a valid position. We want the value live into the
13930b57cec5SDimitry Andric       // instruction or live out of the block, so ask for the previous
13940b57cec5SDimitry Andric       // instruction's live-out.
13950b57cec5SDimitry Andric       const LiveInterval &LI = LIS->getInterval(Reg);
13960b57cec5SDimitry Andric       VNInfo *VNI;
13970b57cec5SDimitry Andric       MachineBasicBlock::const_iterator I =
13980b57cec5SDimitry Andric         nextIfDebug(BotRPTracker.getPos(), BB->end());
13990b57cec5SDimitry Andric       if (I == BB->end())
14000b57cec5SDimitry Andric         VNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB));
14010b57cec5SDimitry Andric       else {
14020b57cec5SDimitry Andric         LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*I));
14030b57cec5SDimitry Andric         VNI = LRQ.valueIn();
14040b57cec5SDimitry Andric       }
14050b57cec5SDimitry Andric       // RegisterPressureTracker guarantees that readsReg is true for LiveUses.
14060b57cec5SDimitry Andric       assert(VNI && "No live value at use.");
14070b57cec5SDimitry Andric       for (const VReg2SUnit &V2SU
14080b57cec5SDimitry Andric            : make_range(VRegUses.find(Reg), VRegUses.end())) {
14090b57cec5SDimitry Andric         SUnit *SU = V2SU.SU;
14100b57cec5SDimitry Andric         // If this use comes before the reaching def, it cannot be a last use,
14110b57cec5SDimitry Andric         // so decrease its pressure change.
14120b57cec5SDimitry Andric         if (!SU->isScheduled && SU != &ExitSU) {
14130b57cec5SDimitry Andric           LiveQueryResult LRQ =
14140b57cec5SDimitry Andric               LI.Query(LIS->getInstructionIndex(*SU->getInstr()));
14150b57cec5SDimitry Andric           if (LRQ.valueIn() == VNI) {
14160b57cec5SDimitry Andric             PressureDiff &PDiff = getPressureDiff(SU);
14170b57cec5SDimitry Andric             PDiff.addPressureChange(Reg, true, &MRI);
14180b57cec5SDimitry Andric             LLVM_DEBUG(dbgs() << "  UpdateRegP: SU(" << SU->NodeNum << ") "
14190b57cec5SDimitry Andric                               << *SU->getInstr();
14200b57cec5SDimitry Andric                        dbgs() << "              to "; PDiff.dump(*TRI););
14210b57cec5SDimitry Andric           }
14220b57cec5SDimitry Andric         }
14230b57cec5SDimitry Andric       }
14240b57cec5SDimitry Andric     }
14250b57cec5SDimitry Andric   }
14260b57cec5SDimitry Andric }
14270b57cec5SDimitry Andric 
14280b57cec5SDimitry Andric void ScheduleDAGMILive::dump() const {
14290b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
14300b57cec5SDimitry Andric   if (EntrySU.getInstr() != nullptr)
14310b57cec5SDimitry Andric     dumpNodeAll(EntrySU);
14320b57cec5SDimitry Andric   for (const SUnit &SU : SUnits) {
14330b57cec5SDimitry Andric     dumpNodeAll(SU);
14340b57cec5SDimitry Andric     if (ShouldTrackPressure) {
14350b57cec5SDimitry Andric       dbgs() << "  Pressure Diff      : ";
14360b57cec5SDimitry Andric       getPressureDiff(&SU).dump(*TRI);
14370b57cec5SDimitry Andric     }
14380b57cec5SDimitry Andric     dbgs() << "  Single Issue       : ";
14390b57cec5SDimitry Andric     if (SchedModel.mustBeginGroup(SU.getInstr()) &&
14400b57cec5SDimitry Andric         SchedModel.mustEndGroup(SU.getInstr()))
14410b57cec5SDimitry Andric       dbgs() << "true;";
14420b57cec5SDimitry Andric     else
14430b57cec5SDimitry Andric       dbgs() << "false;";
14440b57cec5SDimitry Andric     dbgs() << '\n';
14450b57cec5SDimitry Andric   }
14460b57cec5SDimitry Andric   if (ExitSU.getInstr() != nullptr)
14470b57cec5SDimitry Andric     dumpNodeAll(ExitSU);
14480b57cec5SDimitry Andric #endif
14490b57cec5SDimitry Andric }
14500b57cec5SDimitry Andric 
14510b57cec5SDimitry Andric /// schedule - Called back from MachineScheduler::runOnMachineFunction
14520b57cec5SDimitry Andric /// after setting up the current scheduling region. [RegionBegin, RegionEnd)
14530b57cec5SDimitry Andric /// only includes instructions that have DAG nodes, not scheduling boundaries.
14540b57cec5SDimitry Andric ///
14550b57cec5SDimitry Andric /// This is a skeletal driver, with all the functionality pushed into helpers,
14560b57cec5SDimitry Andric /// so that it can be easily extended by experimental schedulers. Generally,
14570b57cec5SDimitry Andric /// implementing MachineSchedStrategy should be sufficient to implement a new
14580b57cec5SDimitry Andric /// scheduling algorithm. However, if a scheduler further subclasses
14590b57cec5SDimitry Andric /// ScheduleDAGMILive then it will want to override this virtual method in order
14600b57cec5SDimitry Andric /// to update any specialized state.
14610b57cec5SDimitry Andric void ScheduleDAGMILive::schedule() {
14620b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "ScheduleDAGMILive::schedule starting\n");
14630b57cec5SDimitry Andric   LLVM_DEBUG(SchedImpl->dumpPolicy());
14640b57cec5SDimitry Andric   buildDAGWithRegPressure();
14650b57cec5SDimitry Andric 
146606c3fb27SDimitry Andric   postProcessDAG();
14670b57cec5SDimitry Andric 
14680b57cec5SDimitry Andric   SmallVector<SUnit*, 8> TopRoots, BotRoots;
14690b57cec5SDimitry Andric   findRootsAndBiasEdges(TopRoots, BotRoots);
14700b57cec5SDimitry Andric 
14710b57cec5SDimitry Andric   // Initialize the strategy before modifying the DAG.
14720b57cec5SDimitry Andric   // This may initialize a DFSResult to be used for queue priority.
14730b57cec5SDimitry Andric   SchedImpl->initialize(this);
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric   LLVM_DEBUG(dump());
14760b57cec5SDimitry Andric   if (PrintDAGs) dump();
14770b57cec5SDimitry Andric   if (ViewMISchedDAGs) viewGraph();
14780b57cec5SDimitry Andric 
14790b57cec5SDimitry Andric   // Initialize ready queues now that the DAG and priority data are finalized.
14800b57cec5SDimitry Andric   initQueues(TopRoots, BotRoots);
14810b57cec5SDimitry Andric 
14820b57cec5SDimitry Andric   bool IsTopNode = false;
14830b57cec5SDimitry Andric   while (true) {
14840b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "** ScheduleDAGMILive::schedule picking next node\n");
14850b57cec5SDimitry Andric     SUnit *SU = SchedImpl->pickNode(IsTopNode);
14860b57cec5SDimitry Andric     if (!SU) break;
14870b57cec5SDimitry Andric 
14880b57cec5SDimitry Andric     assert(!SU->isScheduled && "Node already scheduled");
14890b57cec5SDimitry Andric     if (!checkSchedLimit())
14900b57cec5SDimitry Andric       break;
14910b57cec5SDimitry Andric 
14920b57cec5SDimitry Andric     scheduleMI(SU, IsTopNode);
14930b57cec5SDimitry Andric 
14940b57cec5SDimitry Andric     if (DFSResult) {
14950b57cec5SDimitry Andric       unsigned SubtreeID = DFSResult->getSubtreeID(SU);
14960b57cec5SDimitry Andric       if (!ScheduledTrees.test(SubtreeID)) {
14970b57cec5SDimitry Andric         ScheduledTrees.set(SubtreeID);
14980b57cec5SDimitry Andric         DFSResult->scheduleTree(SubtreeID);
14990b57cec5SDimitry Andric         SchedImpl->scheduleTree(SubtreeID);
15000b57cec5SDimitry Andric       }
15010b57cec5SDimitry Andric     }
15020b57cec5SDimitry Andric 
15030b57cec5SDimitry Andric     // Notify the scheduling strategy after updating the DAG.
15040b57cec5SDimitry Andric     SchedImpl->schedNode(SU, IsTopNode);
15050b57cec5SDimitry Andric 
15060b57cec5SDimitry Andric     updateQueues(SU, IsTopNode);
15070b57cec5SDimitry Andric   }
15080b57cec5SDimitry Andric   assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
15090b57cec5SDimitry Andric 
15100b57cec5SDimitry Andric   placeDebugValues();
15110b57cec5SDimitry Andric 
15120b57cec5SDimitry Andric   LLVM_DEBUG({
15130b57cec5SDimitry Andric     dbgs() << "*** Final schedule for "
15140b57cec5SDimitry Andric            << printMBBReference(*begin()->getParent()) << " ***\n";
15150b57cec5SDimitry Andric     dumpSchedule();
15160b57cec5SDimitry Andric     dbgs() << '\n';
15170b57cec5SDimitry Andric   });
15180b57cec5SDimitry Andric }
15190b57cec5SDimitry Andric 
15200b57cec5SDimitry Andric /// Build the DAG and setup three register pressure trackers.
15210b57cec5SDimitry Andric void ScheduleDAGMILive::buildDAGWithRegPressure() {
15220b57cec5SDimitry Andric   if (!ShouldTrackPressure) {
15230b57cec5SDimitry Andric     RPTracker.reset();
15240b57cec5SDimitry Andric     RegionCriticalPSets.clear();
15250b57cec5SDimitry Andric     buildSchedGraph(AA);
15260b57cec5SDimitry Andric     return;
15270b57cec5SDimitry Andric   }
15280b57cec5SDimitry Andric 
15290b57cec5SDimitry Andric   // Initialize the register pressure tracker used by buildSchedGraph.
15300b57cec5SDimitry Andric   RPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd,
15310b57cec5SDimitry Andric                  ShouldTrackLaneMasks, /*TrackUntiedDefs=*/true);
15320b57cec5SDimitry Andric 
15330b57cec5SDimitry Andric   // Account for liveness generate by the region boundary.
15340b57cec5SDimitry Andric   if (LiveRegionEnd != RegionEnd)
15350b57cec5SDimitry Andric     RPTracker.recede();
15360b57cec5SDimitry Andric 
15370b57cec5SDimitry Andric   // Build the DAG, and compute current register pressure.
15380b57cec5SDimitry Andric   buildSchedGraph(AA, &RPTracker, &SUPressureDiffs, LIS, ShouldTrackLaneMasks);
15390b57cec5SDimitry Andric 
15400b57cec5SDimitry Andric   // Initialize top/bottom trackers after computing region pressure.
15410b57cec5SDimitry Andric   initRegPressure();
15420b57cec5SDimitry Andric }
15430b57cec5SDimitry Andric 
15440b57cec5SDimitry Andric void ScheduleDAGMILive::computeDFSResult() {
15450b57cec5SDimitry Andric   if (!DFSResult)
15460b57cec5SDimitry Andric     DFSResult = new SchedDFSResult(/*BottomU*/true, MinSubtreeSize);
15470b57cec5SDimitry Andric   DFSResult->clear();
15480b57cec5SDimitry Andric   ScheduledTrees.clear();
15490b57cec5SDimitry Andric   DFSResult->resize(SUnits.size());
15500b57cec5SDimitry Andric   DFSResult->compute(SUnits);
15510b57cec5SDimitry Andric   ScheduledTrees.resize(DFSResult->getNumSubtrees());
15520b57cec5SDimitry Andric }
15530b57cec5SDimitry Andric 
15540b57cec5SDimitry Andric /// Compute the max cyclic critical path through the DAG. The scheduling DAG
15550b57cec5SDimitry Andric /// only provides the critical path for single block loops. To handle loops that
15560b57cec5SDimitry Andric /// span blocks, we could use the vreg path latencies provided by
15570b57cec5SDimitry Andric /// MachineTraceMetrics instead. However, MachineTraceMetrics is not currently
15580b57cec5SDimitry Andric /// available for use in the scheduler.
15590b57cec5SDimitry Andric ///
15600b57cec5SDimitry Andric /// The cyclic path estimation identifies a def-use pair that crosses the back
15610b57cec5SDimitry Andric /// edge and considers the depth and height of the nodes. For example, consider
15620b57cec5SDimitry Andric /// the following instruction sequence where each instruction has unit latency
1563e8d8bef9SDimitry Andric /// and defines an eponymous virtual register:
15640b57cec5SDimitry Andric ///
15650b57cec5SDimitry Andric /// a->b(a,c)->c(b)->d(c)->exit
15660b57cec5SDimitry Andric ///
15670b57cec5SDimitry Andric /// The cyclic critical path is a two cycles: b->c->b
15680b57cec5SDimitry Andric /// The acyclic critical path is four cycles: a->b->c->d->exit
15690b57cec5SDimitry Andric /// LiveOutHeight = height(c) = len(c->d->exit) = 2
15700b57cec5SDimitry Andric /// LiveOutDepth = depth(c) + 1 = len(a->b->c) + 1 = 3
15710b57cec5SDimitry Andric /// LiveInHeight = height(b) + 1 = len(b->c->d->exit) + 1 = 4
15720b57cec5SDimitry Andric /// LiveInDepth = depth(b) = len(a->b) = 1
15730b57cec5SDimitry Andric ///
15740b57cec5SDimitry Andric /// LiveOutDepth - LiveInDepth = 3 - 1 = 2
15750b57cec5SDimitry Andric /// LiveInHeight - LiveOutHeight = 4 - 2 = 2
15760b57cec5SDimitry Andric /// CyclicCriticalPath = min(2, 2) = 2
15770b57cec5SDimitry Andric ///
15780b57cec5SDimitry Andric /// This could be relevant to PostRA scheduling, but is currently implemented
15790b57cec5SDimitry Andric /// assuming LiveIntervals.
15800b57cec5SDimitry Andric unsigned ScheduleDAGMILive::computeCyclicCriticalPath() {
15810b57cec5SDimitry Andric   // This only applies to single block loop.
15820b57cec5SDimitry Andric   if (!BB->isSuccessor(BB))
15830b57cec5SDimitry Andric     return 0;
15840b57cec5SDimitry Andric 
15850b57cec5SDimitry Andric   unsigned MaxCyclicLatency = 0;
15860b57cec5SDimitry Andric   // Visit each live out vreg def to find def/use pairs that cross iterations.
15870b57cec5SDimitry Andric   for (const RegisterMaskPair &P : RPTracker.getPressure().LiveOutRegs) {
1588e8d8bef9SDimitry Andric     Register Reg = P.RegUnit;
1589bdd1243dSDimitry Andric     if (!Reg.isVirtual())
15900b57cec5SDimitry Andric       continue;
15910b57cec5SDimitry Andric     const LiveInterval &LI = LIS->getInterval(Reg);
15920b57cec5SDimitry Andric     const VNInfo *DefVNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB));
15930b57cec5SDimitry Andric     if (!DefVNI)
15940b57cec5SDimitry Andric       continue;
15950b57cec5SDimitry Andric 
15960b57cec5SDimitry Andric     MachineInstr *DefMI = LIS->getInstructionFromIndex(DefVNI->def);
15970b57cec5SDimitry Andric     const SUnit *DefSU = getSUnit(DefMI);
15980b57cec5SDimitry Andric     if (!DefSU)
15990b57cec5SDimitry Andric       continue;
16000b57cec5SDimitry Andric 
16010b57cec5SDimitry Andric     unsigned LiveOutHeight = DefSU->getHeight();
16020b57cec5SDimitry Andric     unsigned LiveOutDepth = DefSU->getDepth() + DefSU->Latency;
16030b57cec5SDimitry Andric     // Visit all local users of the vreg def.
16040b57cec5SDimitry Andric     for (const VReg2SUnit &V2SU
16050b57cec5SDimitry Andric          : make_range(VRegUses.find(Reg), VRegUses.end())) {
16060b57cec5SDimitry Andric       SUnit *SU = V2SU.SU;
16070b57cec5SDimitry Andric       if (SU == &ExitSU)
16080b57cec5SDimitry Andric         continue;
16090b57cec5SDimitry Andric 
16100b57cec5SDimitry Andric       // Only consider uses of the phi.
16110b57cec5SDimitry Andric       LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*SU->getInstr()));
16120b57cec5SDimitry Andric       if (!LRQ.valueIn()->isPHIDef())
16130b57cec5SDimitry Andric         continue;
16140b57cec5SDimitry Andric 
16150b57cec5SDimitry Andric       // Assume that a path spanning two iterations is a cycle, which could
16160b57cec5SDimitry Andric       // overestimate in strange cases. This allows cyclic latency to be
16170b57cec5SDimitry Andric       // estimated as the minimum slack of the vreg's depth or height.
16180b57cec5SDimitry Andric       unsigned CyclicLatency = 0;
16190b57cec5SDimitry Andric       if (LiveOutDepth > SU->getDepth())
16200b57cec5SDimitry Andric         CyclicLatency = LiveOutDepth - SU->getDepth();
16210b57cec5SDimitry Andric 
16220b57cec5SDimitry Andric       unsigned LiveInHeight = SU->getHeight() + DefSU->Latency;
16230b57cec5SDimitry Andric       if (LiveInHeight > LiveOutHeight) {
16240b57cec5SDimitry Andric         if (LiveInHeight - LiveOutHeight < CyclicLatency)
16250b57cec5SDimitry Andric           CyclicLatency = LiveInHeight - LiveOutHeight;
16260b57cec5SDimitry Andric       } else
16270b57cec5SDimitry Andric         CyclicLatency = 0;
16280b57cec5SDimitry Andric 
16290b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Cyclic Path: SU(" << DefSU->NodeNum << ") -> SU("
16300b57cec5SDimitry Andric                         << SU->NodeNum << ") = " << CyclicLatency << "c\n");
16310b57cec5SDimitry Andric       if (CyclicLatency > MaxCyclicLatency)
16320b57cec5SDimitry Andric         MaxCyclicLatency = CyclicLatency;
16330b57cec5SDimitry Andric     }
16340b57cec5SDimitry Andric   }
16350b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Cyclic Critical Path: " << MaxCyclicLatency << "c\n");
16360b57cec5SDimitry Andric   return MaxCyclicLatency;
16370b57cec5SDimitry Andric }
16380b57cec5SDimitry Andric 
16390b57cec5SDimitry Andric /// Release ExitSU predecessors and setup scheduler queues. Re-position
16400b57cec5SDimitry Andric /// the Top RP tracker in case the region beginning has changed.
16410b57cec5SDimitry Andric void ScheduleDAGMILive::initQueues(ArrayRef<SUnit*> TopRoots,
16420b57cec5SDimitry Andric                                    ArrayRef<SUnit*> BotRoots) {
16430b57cec5SDimitry Andric   ScheduleDAGMI::initQueues(TopRoots, BotRoots);
16440b57cec5SDimitry Andric   if (ShouldTrackPressure) {
16450b57cec5SDimitry Andric     assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker");
16460b57cec5SDimitry Andric     TopRPTracker.setPos(CurrentTop);
16470b57cec5SDimitry Andric   }
16480b57cec5SDimitry Andric }
16490b57cec5SDimitry Andric 
16500b57cec5SDimitry Andric /// Move an instruction and update register pressure.
16510b57cec5SDimitry Andric void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) {
16520b57cec5SDimitry Andric   // Move the instruction to its new location in the instruction stream.
16530b57cec5SDimitry Andric   MachineInstr *MI = SU->getInstr();
16540b57cec5SDimitry Andric 
16550b57cec5SDimitry Andric   if (IsTopNode) {
16560b57cec5SDimitry Andric     assert(SU->isTopReady() && "node still has unscheduled dependencies");
16570b57cec5SDimitry Andric     if (&*CurrentTop == MI)
16580b57cec5SDimitry Andric       CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom);
16590b57cec5SDimitry Andric     else {
16600b57cec5SDimitry Andric       moveInstruction(MI, CurrentTop);
16610b57cec5SDimitry Andric       TopRPTracker.setPos(MI);
16620b57cec5SDimitry Andric     }
16630b57cec5SDimitry Andric 
16640b57cec5SDimitry Andric     if (ShouldTrackPressure) {
16650b57cec5SDimitry Andric       // Update top scheduled pressure.
16660b57cec5SDimitry Andric       RegisterOperands RegOpers;
1667*0fca6ea1SDimitry Andric       RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks,
1668*0fca6ea1SDimitry Andric                        /*IgnoreDead=*/false);
16690b57cec5SDimitry Andric       if (ShouldTrackLaneMasks) {
16700b57cec5SDimitry Andric         // Adjust liveness and add missing dead+read-undef flags.
16710b57cec5SDimitry Andric         SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
16720b57cec5SDimitry Andric         RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
16730b57cec5SDimitry Andric       } else {
16740b57cec5SDimitry Andric         // Adjust for missing dead-def flags.
16750b57cec5SDimitry Andric         RegOpers.detectDeadDefs(*MI, *LIS);
16760b57cec5SDimitry Andric       }
16770b57cec5SDimitry Andric 
16780b57cec5SDimitry Andric       TopRPTracker.advance(RegOpers);
16790b57cec5SDimitry Andric       assert(TopRPTracker.getPos() == CurrentTop && "out of sync");
16800b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Top Pressure:\n"; dumpRegSetPressure(
16810b57cec5SDimitry Andric                      TopRPTracker.getRegSetPressureAtPos(), TRI););
16820b57cec5SDimitry Andric 
16830b57cec5SDimitry Andric       updateScheduledPressure(SU, TopRPTracker.getPressure().MaxSetPressure);
16840b57cec5SDimitry Andric     }
16850b57cec5SDimitry Andric   } else {
16860b57cec5SDimitry Andric     assert(SU->isBottomReady() && "node still has unscheduled dependencies");
16870b57cec5SDimitry Andric     MachineBasicBlock::iterator priorII =
16880b57cec5SDimitry Andric       priorNonDebug(CurrentBottom, CurrentTop);
16890b57cec5SDimitry Andric     if (&*priorII == MI)
16900b57cec5SDimitry Andric       CurrentBottom = priorII;
16910b57cec5SDimitry Andric     else {
16920b57cec5SDimitry Andric       if (&*CurrentTop == MI) {
16930b57cec5SDimitry Andric         CurrentTop = nextIfDebug(++CurrentTop, priorII);
16940b57cec5SDimitry Andric         TopRPTracker.setPos(CurrentTop);
16950b57cec5SDimitry Andric       }
16960b57cec5SDimitry Andric       moveInstruction(MI, CurrentBottom);
16970b57cec5SDimitry Andric       CurrentBottom = MI;
16980b57cec5SDimitry Andric       BotRPTracker.setPos(CurrentBottom);
16990b57cec5SDimitry Andric     }
17000b57cec5SDimitry Andric     if (ShouldTrackPressure) {
17010b57cec5SDimitry Andric       RegisterOperands RegOpers;
1702*0fca6ea1SDimitry Andric       RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks,
1703*0fca6ea1SDimitry Andric                        /*IgnoreDead=*/false);
17040b57cec5SDimitry Andric       if (ShouldTrackLaneMasks) {
17050b57cec5SDimitry Andric         // Adjust liveness and add missing dead+read-undef flags.
17060b57cec5SDimitry Andric         SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
17070b57cec5SDimitry Andric         RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
17080b57cec5SDimitry Andric       } else {
17090b57cec5SDimitry Andric         // Adjust for missing dead-def flags.
17100b57cec5SDimitry Andric         RegOpers.detectDeadDefs(*MI, *LIS);
17110b57cec5SDimitry Andric       }
17120b57cec5SDimitry Andric 
17130b57cec5SDimitry Andric       if (BotRPTracker.getPos() != CurrentBottom)
17140b57cec5SDimitry Andric         BotRPTracker.recedeSkipDebugValues();
17150b57cec5SDimitry Andric       SmallVector<RegisterMaskPair, 8> LiveUses;
17160b57cec5SDimitry Andric       BotRPTracker.recede(RegOpers, &LiveUses);
17170b57cec5SDimitry Andric       assert(BotRPTracker.getPos() == CurrentBottom && "out of sync");
17180b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Bottom Pressure:\n"; dumpRegSetPressure(
17190b57cec5SDimitry Andric                      BotRPTracker.getRegSetPressureAtPos(), TRI););
17200b57cec5SDimitry Andric 
17210b57cec5SDimitry Andric       updateScheduledPressure(SU, BotRPTracker.getPressure().MaxSetPressure);
17220b57cec5SDimitry Andric       updatePressureDiffs(LiveUses);
17230b57cec5SDimitry Andric     }
17240b57cec5SDimitry Andric   }
17250b57cec5SDimitry Andric }
17260b57cec5SDimitry Andric 
17270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17280b57cec5SDimitry Andric // BaseMemOpClusterMutation - DAG post-processing to cluster loads or stores.
17290b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17300b57cec5SDimitry Andric 
17310b57cec5SDimitry Andric namespace {
17320b57cec5SDimitry Andric 
17330b57cec5SDimitry Andric /// Post-process the DAG to create cluster edges between neighboring
17340b57cec5SDimitry Andric /// loads or between neighboring stores.
17350b57cec5SDimitry Andric class BaseMemOpClusterMutation : public ScheduleDAGMutation {
17360b57cec5SDimitry Andric   struct MemOpInfo {
17370b57cec5SDimitry Andric     SUnit *SU;
17385ffd83dbSDimitry Andric     SmallVector<const MachineOperand *, 4> BaseOps;
17390b57cec5SDimitry Andric     int64_t Offset;
1740*0fca6ea1SDimitry Andric     LocationSize Width;
17415f757f3fSDimitry Andric     bool OffsetIsScalable;
17420b57cec5SDimitry Andric 
17435ffd83dbSDimitry Andric     MemOpInfo(SUnit *SU, ArrayRef<const MachineOperand *> BaseOps,
1744*0fca6ea1SDimitry Andric               int64_t Offset, bool OffsetIsScalable, LocationSize Width)
17455ffd83dbSDimitry Andric         : SU(SU), BaseOps(BaseOps.begin(), BaseOps.end()), Offset(Offset),
17465f757f3fSDimitry Andric           Width(Width), OffsetIsScalable(OffsetIsScalable) {}
17470b57cec5SDimitry Andric 
17485ffd83dbSDimitry Andric     static bool Compare(const MachineOperand *const &A,
17495ffd83dbSDimitry Andric                         const MachineOperand *const &B) {
17505ffd83dbSDimitry Andric       if (A->getType() != B->getType())
17515ffd83dbSDimitry Andric         return A->getType() < B->getType();
17525ffd83dbSDimitry Andric       if (A->isReg())
17535ffd83dbSDimitry Andric         return A->getReg() < B->getReg();
17545ffd83dbSDimitry Andric       if (A->isFI()) {
17555ffd83dbSDimitry Andric         const MachineFunction &MF = *A->getParent()->getParent()->getParent();
17560b57cec5SDimitry Andric         const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
17570b57cec5SDimitry Andric         bool StackGrowsDown = TFI.getStackGrowthDirection() ==
17580b57cec5SDimitry Andric                               TargetFrameLowering::StackGrowsDown;
17595ffd83dbSDimitry Andric         return StackGrowsDown ? A->getIndex() > B->getIndex()
17605ffd83dbSDimitry Andric                               : A->getIndex() < B->getIndex();
17610b57cec5SDimitry Andric       }
17620b57cec5SDimitry Andric 
17630b57cec5SDimitry Andric       llvm_unreachable("MemOpClusterMutation only supports register or frame "
17640b57cec5SDimitry Andric                        "index bases.");
17650b57cec5SDimitry Andric     }
17665ffd83dbSDimitry Andric 
17675ffd83dbSDimitry Andric     bool operator<(const MemOpInfo &RHS) const {
17685ffd83dbSDimitry Andric       // FIXME: Don't compare everything twice. Maybe use C++20 three way
17695ffd83dbSDimitry Andric       // comparison instead when it's available.
17705ffd83dbSDimitry Andric       if (std::lexicographical_compare(BaseOps.begin(), BaseOps.end(),
17715ffd83dbSDimitry Andric                                        RHS.BaseOps.begin(), RHS.BaseOps.end(),
17725ffd83dbSDimitry Andric                                        Compare))
17735ffd83dbSDimitry Andric         return true;
17745ffd83dbSDimitry Andric       if (std::lexicographical_compare(RHS.BaseOps.begin(), RHS.BaseOps.end(),
17755ffd83dbSDimitry Andric                                        BaseOps.begin(), BaseOps.end(), Compare))
17765ffd83dbSDimitry Andric         return false;
17775ffd83dbSDimitry Andric       if (Offset != RHS.Offset)
17785ffd83dbSDimitry Andric         return Offset < RHS.Offset;
17795ffd83dbSDimitry Andric       return SU->NodeNum < RHS.SU->NodeNum;
17805ffd83dbSDimitry Andric     }
17810b57cec5SDimitry Andric   };
17820b57cec5SDimitry Andric 
17830b57cec5SDimitry Andric   const TargetInstrInfo *TII;
17840b57cec5SDimitry Andric   const TargetRegisterInfo *TRI;
17850b57cec5SDimitry Andric   bool IsLoad;
17867a6dacacSDimitry Andric   bool ReorderWhileClustering;
17870b57cec5SDimitry Andric 
17880b57cec5SDimitry Andric public:
17890b57cec5SDimitry Andric   BaseMemOpClusterMutation(const TargetInstrInfo *tii,
17907a6dacacSDimitry Andric                            const TargetRegisterInfo *tri, bool IsLoad,
17917a6dacacSDimitry Andric                            bool ReorderWhileClustering)
17927a6dacacSDimitry Andric       : TII(tii), TRI(tri), IsLoad(IsLoad),
17937a6dacacSDimitry Andric         ReorderWhileClustering(ReorderWhileClustering) {}
17940b57cec5SDimitry Andric 
17950b57cec5SDimitry Andric   void apply(ScheduleDAGInstrs *DAGInstrs) override;
17960b57cec5SDimitry Andric 
17970b57cec5SDimitry Andric protected:
1798e8d8bef9SDimitry Andric   void clusterNeighboringMemOps(ArrayRef<MemOpInfo> MemOps, bool FastCluster,
1799e8d8bef9SDimitry Andric                                 ScheduleDAGInstrs *DAG);
1800e8d8bef9SDimitry Andric   void collectMemOpRecords(std::vector<SUnit> &SUnits,
1801e8d8bef9SDimitry Andric                            SmallVectorImpl<MemOpInfo> &MemOpRecords);
1802e8d8bef9SDimitry Andric   bool groupMemOps(ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG,
1803e8d8bef9SDimitry Andric                    DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups);
18040b57cec5SDimitry Andric };
18050b57cec5SDimitry Andric 
18060b57cec5SDimitry Andric class StoreClusterMutation : public BaseMemOpClusterMutation {
18070b57cec5SDimitry Andric public:
18080b57cec5SDimitry Andric   StoreClusterMutation(const TargetInstrInfo *tii,
18097a6dacacSDimitry Andric                        const TargetRegisterInfo *tri,
18107a6dacacSDimitry Andric                        bool ReorderWhileClustering)
18117a6dacacSDimitry Andric       : BaseMemOpClusterMutation(tii, tri, false, ReorderWhileClustering) {}
18120b57cec5SDimitry Andric };
18130b57cec5SDimitry Andric 
18140b57cec5SDimitry Andric class LoadClusterMutation : public BaseMemOpClusterMutation {
18150b57cec5SDimitry Andric public:
18167a6dacacSDimitry Andric   LoadClusterMutation(const TargetInstrInfo *tii, const TargetRegisterInfo *tri,
18177a6dacacSDimitry Andric                       bool ReorderWhileClustering)
18187a6dacacSDimitry Andric       : BaseMemOpClusterMutation(tii, tri, true, ReorderWhileClustering) {}
18190b57cec5SDimitry Andric };
18200b57cec5SDimitry Andric 
18210b57cec5SDimitry Andric } // end anonymous namespace
18220b57cec5SDimitry Andric 
18230b57cec5SDimitry Andric namespace llvm {
18240b57cec5SDimitry Andric 
18250b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
18260b57cec5SDimitry Andric createLoadClusterDAGMutation(const TargetInstrInfo *TII,
18277a6dacacSDimitry Andric                              const TargetRegisterInfo *TRI,
18287a6dacacSDimitry Andric                              bool ReorderWhileClustering) {
18297a6dacacSDimitry Andric   return EnableMemOpCluster ? std::make_unique<LoadClusterMutation>(
18307a6dacacSDimitry Andric                                   TII, TRI, ReorderWhileClustering)
18310b57cec5SDimitry Andric                             : nullptr;
18320b57cec5SDimitry Andric }
18330b57cec5SDimitry Andric 
18340b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
18350b57cec5SDimitry Andric createStoreClusterDAGMutation(const TargetInstrInfo *TII,
18367a6dacacSDimitry Andric                               const TargetRegisterInfo *TRI,
18377a6dacacSDimitry Andric                               bool ReorderWhileClustering) {
18387a6dacacSDimitry Andric   return EnableMemOpCluster ? std::make_unique<StoreClusterMutation>(
18397a6dacacSDimitry Andric                                   TII, TRI, ReorderWhileClustering)
18400b57cec5SDimitry Andric                             : nullptr;
18410b57cec5SDimitry Andric }
18420b57cec5SDimitry Andric 
18430b57cec5SDimitry Andric } // end namespace llvm
18440b57cec5SDimitry Andric 
1845e8d8bef9SDimitry Andric // Sorting all the loads/stores first, then for each load/store, checking the
1846e8d8bef9SDimitry Andric // following load/store one by one, until reach the first non-dependent one and
1847e8d8bef9SDimitry Andric // call target hook to see if they can cluster.
1848e8d8bef9SDimitry Andric // If FastCluster is enabled, we assume that, all the loads/stores have been
1849e8d8bef9SDimitry Andric // preprocessed and now, they didn't have dependencies on each other.
18500b57cec5SDimitry Andric void BaseMemOpClusterMutation::clusterNeighboringMemOps(
1851e8d8bef9SDimitry Andric     ArrayRef<MemOpInfo> MemOpRecords, bool FastCluster,
1852e8d8bef9SDimitry Andric     ScheduleDAGInstrs *DAG) {
1853e8d8bef9SDimitry Andric   // Keep track of the current cluster length and bytes for each SUnit.
1854e8d8bef9SDimitry Andric   DenseMap<unsigned, std::pair<unsigned, unsigned>> SUnit2ClusterInfo;
18555ffd83dbSDimitry Andric 
18565ffd83dbSDimitry Andric   // At this point, `MemOpRecords` array must hold atleast two mem ops. Try to
18575ffd83dbSDimitry Andric   // cluster mem ops collected within `MemOpRecords` array.
18580b57cec5SDimitry Andric   for (unsigned Idx = 0, End = MemOpRecords.size(); Idx < (End - 1); ++Idx) {
18595ffd83dbSDimitry Andric     // Decision to cluster mem ops is taken based on target dependent logic
18605ffd83dbSDimitry Andric     auto MemOpa = MemOpRecords[Idx];
1861e8d8bef9SDimitry Andric 
1862e8d8bef9SDimitry Andric     // Seek for the next load/store to do the cluster.
1863e8d8bef9SDimitry Andric     unsigned NextIdx = Idx + 1;
1864e8d8bef9SDimitry Andric     for (; NextIdx < End; ++NextIdx)
1865e8d8bef9SDimitry Andric       // Skip if MemOpb has been clustered already or has dependency with
1866e8d8bef9SDimitry Andric       // MemOpa.
1867e8d8bef9SDimitry Andric       if (!SUnit2ClusterInfo.count(MemOpRecords[NextIdx].SU->NodeNum) &&
1868e8d8bef9SDimitry Andric           (FastCluster ||
1869e8d8bef9SDimitry Andric            (!DAG->IsReachable(MemOpRecords[NextIdx].SU, MemOpa.SU) &&
1870e8d8bef9SDimitry Andric             !DAG->IsReachable(MemOpa.SU, MemOpRecords[NextIdx].SU))))
1871e8d8bef9SDimitry Andric         break;
1872e8d8bef9SDimitry Andric     if (NextIdx == End)
18735ffd83dbSDimitry Andric       continue;
1874e8d8bef9SDimitry Andric 
1875e8d8bef9SDimitry Andric     auto MemOpb = MemOpRecords[NextIdx];
1876e8d8bef9SDimitry Andric     unsigned ClusterLength = 2;
1877*0fca6ea1SDimitry Andric     unsigned CurrentClusterBytes = MemOpa.Width.getValue().getKnownMinValue() +
1878*0fca6ea1SDimitry Andric                                    MemOpb.Width.getValue().getKnownMinValue();
1879e8d8bef9SDimitry Andric     if (SUnit2ClusterInfo.count(MemOpa.SU->NodeNum)) {
1880e8d8bef9SDimitry Andric       ClusterLength = SUnit2ClusterInfo[MemOpa.SU->NodeNum].first + 1;
1881*0fca6ea1SDimitry Andric       CurrentClusterBytes = SUnit2ClusterInfo[MemOpa.SU->NodeNum].second +
1882*0fca6ea1SDimitry Andric                             MemOpb.Width.getValue().getKnownMinValue();
18835ffd83dbSDimitry Andric     }
18845ffd83dbSDimitry Andric 
18855f757f3fSDimitry Andric     if (!TII->shouldClusterMemOps(MemOpa.BaseOps, MemOpa.Offset,
18865f757f3fSDimitry Andric                                   MemOpa.OffsetIsScalable, MemOpb.BaseOps,
18875f757f3fSDimitry Andric                                   MemOpb.Offset, MemOpb.OffsetIsScalable,
18885f757f3fSDimitry Andric                                   ClusterLength, CurrentClusterBytes))
1889e8d8bef9SDimitry Andric       continue;
1890e8d8bef9SDimitry Andric 
18915ffd83dbSDimitry Andric     SUnit *SUa = MemOpa.SU;
18925ffd83dbSDimitry Andric     SUnit *SUb = MemOpb.SU;
18937a6dacacSDimitry Andric     if (!ReorderWhileClustering && SUa->NodeNum > SUb->NodeNum)
1894480093f4SDimitry Andric       std::swap(SUa, SUb);
18955ffd83dbSDimitry Andric 
18965ffd83dbSDimitry Andric     // FIXME: Is this check really required?
1897e8d8bef9SDimitry Andric     if (!DAG->addEdge(SUb, SDep(SUa, SDep::Cluster)))
18985ffd83dbSDimitry Andric       continue;
18995ffd83dbSDimitry Andric 
19000b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Cluster ld/st SU(" << SUa->NodeNum << ") - SU("
19010b57cec5SDimitry Andric                       << SUb->NodeNum << ")\n");
1902e8d8bef9SDimitry Andric     ++NumClustered;
19035ffd83dbSDimitry Andric 
1904e8d8bef9SDimitry Andric     if (IsLoad) {
19050b57cec5SDimitry Andric       // Copy successor edges from SUa to SUb. Interleaving computation
19060b57cec5SDimitry Andric       // dependent on SUa can prevent load combining due to register reuse.
19075ffd83dbSDimitry Andric       // Predecessor edges do not need to be copied from SUb to SUa since
19085ffd83dbSDimitry Andric       // nearby loads should have effectively the same inputs.
19090b57cec5SDimitry Andric       for (const SDep &Succ : SUa->Succs) {
19100b57cec5SDimitry Andric         if (Succ.getSUnit() == SUb)
19110b57cec5SDimitry Andric           continue;
19120b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "  Copy Succ SU(" << Succ.getSUnit()->NodeNum
19130b57cec5SDimitry Andric                           << ")\n");
19140b57cec5SDimitry Andric         DAG->addEdge(Succ.getSUnit(), SDep(SUb, SDep::Artificial));
19150b57cec5SDimitry Andric       }
1916e8d8bef9SDimitry Andric     } else {
1917e8d8bef9SDimitry Andric       // Copy predecessor edges from SUb to SUa to avoid the SUnits that
1918e8d8bef9SDimitry Andric       // SUb dependent on scheduled in-between SUb and SUa. Successor edges
1919e8d8bef9SDimitry Andric       // do not need to be copied from SUa to SUb since no one will depend
1920e8d8bef9SDimitry Andric       // on stores.
1921e8d8bef9SDimitry Andric       // Notice that, we don't need to care about the memory dependency as
1922e8d8bef9SDimitry Andric       // we won't try to cluster them if they have any memory dependency.
1923e8d8bef9SDimitry Andric       for (const SDep &Pred : SUb->Preds) {
1924e8d8bef9SDimitry Andric         if (Pred.getSUnit() == SUa)
1925e8d8bef9SDimitry Andric           continue;
1926e8d8bef9SDimitry Andric         LLVM_DEBUG(dbgs() << "  Copy Pred SU(" << Pred.getSUnit()->NodeNum
1927e8d8bef9SDimitry Andric                           << ")\n");
1928e8d8bef9SDimitry Andric         DAG->addEdge(SUa, SDep(Pred.getSUnit(), SDep::Artificial));
1929e8d8bef9SDimitry Andric       }
1930e8d8bef9SDimitry Andric     }
1931e8d8bef9SDimitry Andric 
1932e8d8bef9SDimitry Andric     SUnit2ClusterInfo[MemOpb.SU->NodeNum] = {ClusterLength,
1933e8d8bef9SDimitry Andric                                              CurrentClusterBytes};
19345ffd83dbSDimitry Andric 
19355ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "  Curr cluster length: " << ClusterLength
19365ffd83dbSDimitry Andric                       << ", Curr cluster bytes: " << CurrentClusterBytes
19375ffd83dbSDimitry Andric                       << "\n");
19380b57cec5SDimitry Andric   }
19390b57cec5SDimitry Andric }
19400b57cec5SDimitry Andric 
1941e8d8bef9SDimitry Andric void BaseMemOpClusterMutation::collectMemOpRecords(
1942e8d8bef9SDimitry Andric     std::vector<SUnit> &SUnits, SmallVectorImpl<MemOpInfo> &MemOpRecords) {
1943e8d8bef9SDimitry Andric   for (auto &SU : SUnits) {
19440b57cec5SDimitry Andric     if ((IsLoad && !SU.getInstr()->mayLoad()) ||
19450b57cec5SDimitry Andric         (!IsLoad && !SU.getInstr()->mayStore()))
19460b57cec5SDimitry Andric       continue;
19470b57cec5SDimitry Andric 
1948e8d8bef9SDimitry Andric     const MachineInstr &MI = *SU.getInstr();
1949e8d8bef9SDimitry Andric     SmallVector<const MachineOperand *, 4> BaseOps;
1950e8d8bef9SDimitry Andric     int64_t Offset;
1951e8d8bef9SDimitry Andric     bool OffsetIsScalable;
1952*0fca6ea1SDimitry Andric     LocationSize Width = 0;
1953e8d8bef9SDimitry Andric     if (TII->getMemOperandsWithOffsetWidth(MI, BaseOps, Offset,
1954e8d8bef9SDimitry Andric                                            OffsetIsScalable, Width, TRI)) {
19555f757f3fSDimitry Andric       MemOpRecords.push_back(
19565f757f3fSDimitry Andric           MemOpInfo(&SU, BaseOps, Offset, OffsetIsScalable, Width));
1957e8d8bef9SDimitry Andric 
1958e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "Num BaseOps: " << BaseOps.size() << ", Offset: "
1959e8d8bef9SDimitry Andric                         << Offset << ", OffsetIsScalable: " << OffsetIsScalable
1960e8d8bef9SDimitry Andric                         << ", Width: " << Width << "\n");
1961e8d8bef9SDimitry Andric     }
1962e8d8bef9SDimitry Andric #ifndef NDEBUG
1963fcaf7f86SDimitry Andric     for (const auto *Op : BaseOps)
1964e8d8bef9SDimitry Andric       assert(Op);
1965e8d8bef9SDimitry Andric #endif
1966e8d8bef9SDimitry Andric   }
1967e8d8bef9SDimitry Andric }
1968e8d8bef9SDimitry Andric 
1969e8d8bef9SDimitry Andric bool BaseMemOpClusterMutation::groupMemOps(
1970e8d8bef9SDimitry Andric     ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG,
1971e8d8bef9SDimitry Andric     DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups) {
1972e8d8bef9SDimitry Andric   bool FastCluster =
1973e8d8bef9SDimitry Andric       ForceFastCluster ||
1974e8d8bef9SDimitry Andric       MemOps.size() * DAG->SUnits.size() / 1000 > FastClusterThreshold;
1975e8d8bef9SDimitry Andric 
1976e8d8bef9SDimitry Andric   for (const auto &MemOp : MemOps) {
19770b57cec5SDimitry Andric     unsigned ChainPredID = DAG->SUnits.size();
1978e8d8bef9SDimitry Andric     if (FastCluster) {
1979e8d8bef9SDimitry Andric       for (const SDep &Pred : MemOp.SU->Preds) {
1980e8d8bef9SDimitry Andric         // We only want to cluster the mem ops that have the same ctrl(non-data)
1981e8d8bef9SDimitry Andric         // pred so that they didn't have ctrl dependency for each other. But for
1982e8d8bef9SDimitry Andric         // store instrs, we can still cluster them if the pred is load instr.
1983e8d8bef9SDimitry Andric         if ((Pred.isCtrl() &&
1984e8d8bef9SDimitry Andric              (IsLoad ||
1985e8d8bef9SDimitry Andric               (Pred.getSUnit() && Pred.getSUnit()->getInstr()->mayStore()))) &&
1986e8d8bef9SDimitry Andric             !Pred.isArtificial()) {
19870b57cec5SDimitry Andric           ChainPredID = Pred.getSUnit()->NodeNum;
19880b57cec5SDimitry Andric           break;
19890b57cec5SDimitry Andric         }
19900b57cec5SDimitry Andric       }
1991e8d8bef9SDimitry Andric     } else
1992e8d8bef9SDimitry Andric       ChainPredID = 0;
1993e8d8bef9SDimitry Andric 
1994e8d8bef9SDimitry Andric     Groups[ChainPredID].push_back(MemOp);
1995e8d8bef9SDimitry Andric   }
1996e8d8bef9SDimitry Andric   return FastCluster;
19970b57cec5SDimitry Andric }
19980b57cec5SDimitry Andric 
1999e8d8bef9SDimitry Andric /// Callback from DAG postProcessing to create cluster edges for loads/stores.
2000e8d8bef9SDimitry Andric void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAG) {
2001e8d8bef9SDimitry Andric   // Collect all the clusterable loads/stores
2002e8d8bef9SDimitry Andric   SmallVector<MemOpInfo, 32> MemOpRecords;
2003e8d8bef9SDimitry Andric   collectMemOpRecords(DAG->SUnits, MemOpRecords);
2004e8d8bef9SDimitry Andric 
2005e8d8bef9SDimitry Andric   if (MemOpRecords.size() < 2)
2006e8d8bef9SDimitry Andric     return;
2007e8d8bef9SDimitry Andric 
2008e8d8bef9SDimitry Andric   // Put the loads/stores without dependency into the same group with some
2009e8d8bef9SDimitry Andric   // heuristic if the DAG is too complex to avoid compiling time blow up.
2010e8d8bef9SDimitry Andric   // Notice that, some fusion pair could be lost with this.
2011e8d8bef9SDimitry Andric   DenseMap<unsigned, SmallVector<MemOpInfo, 32>> Groups;
2012e8d8bef9SDimitry Andric   bool FastCluster = groupMemOps(MemOpRecords, DAG, Groups);
2013e8d8bef9SDimitry Andric 
2014e8d8bef9SDimitry Andric   for (auto &Group : Groups) {
2015e8d8bef9SDimitry Andric     // Sorting the loads/stores, so that, we can stop the cluster as early as
2016e8d8bef9SDimitry Andric     // possible.
2017e8d8bef9SDimitry Andric     llvm::sort(Group.second);
2018e8d8bef9SDimitry Andric 
2019e8d8bef9SDimitry Andric     // Trying to cluster all the neighboring loads/stores.
2020e8d8bef9SDimitry Andric     clusterNeighboringMemOps(Group.second, FastCluster, DAG);
2021e8d8bef9SDimitry Andric   }
20220b57cec5SDimitry Andric }
20230b57cec5SDimitry Andric 
20240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
20250b57cec5SDimitry Andric // CopyConstrain - DAG post-processing to encourage copy elimination.
20260b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
20270b57cec5SDimitry Andric 
20280b57cec5SDimitry Andric namespace {
20290b57cec5SDimitry Andric 
20300b57cec5SDimitry Andric /// Post-process the DAG to create weak edges from all uses of a copy to
20310b57cec5SDimitry Andric /// the one use that defines the copy's source vreg, most likely an induction
20320b57cec5SDimitry Andric /// variable increment.
20330b57cec5SDimitry Andric class CopyConstrain : public ScheduleDAGMutation {
20340b57cec5SDimitry Andric   // Transient state.
20350b57cec5SDimitry Andric   SlotIndex RegionBeginIdx;
20360b57cec5SDimitry Andric 
20370b57cec5SDimitry Andric   // RegionEndIdx is the slot index of the last non-debug instruction in the
20380b57cec5SDimitry Andric   // scheduling region. So we may have RegionBeginIdx == RegionEndIdx.
20390b57cec5SDimitry Andric   SlotIndex RegionEndIdx;
20400b57cec5SDimitry Andric 
20410b57cec5SDimitry Andric public:
20420b57cec5SDimitry Andric   CopyConstrain(const TargetInstrInfo *, const TargetRegisterInfo *) {}
20430b57cec5SDimitry Andric 
20440b57cec5SDimitry Andric   void apply(ScheduleDAGInstrs *DAGInstrs) override;
20450b57cec5SDimitry Andric 
20460b57cec5SDimitry Andric protected:
20470b57cec5SDimitry Andric   void constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG);
20480b57cec5SDimitry Andric };
20490b57cec5SDimitry Andric 
20500b57cec5SDimitry Andric } // end anonymous namespace
20510b57cec5SDimitry Andric 
20520b57cec5SDimitry Andric namespace llvm {
20530b57cec5SDimitry Andric 
20540b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
20550b57cec5SDimitry Andric createCopyConstrainDAGMutation(const TargetInstrInfo *TII,
20560b57cec5SDimitry Andric                                const TargetRegisterInfo *TRI) {
20578bcb0991SDimitry Andric   return std::make_unique<CopyConstrain>(TII, TRI);
20580b57cec5SDimitry Andric }
20590b57cec5SDimitry Andric 
20600b57cec5SDimitry Andric } // end namespace llvm
20610b57cec5SDimitry Andric 
20620b57cec5SDimitry Andric /// constrainLocalCopy handles two possibilities:
20630b57cec5SDimitry Andric /// 1) Local src:
20640b57cec5SDimitry Andric /// I0:     = dst
20650b57cec5SDimitry Andric /// I1: src = ...
20660b57cec5SDimitry Andric /// I2:     = dst
20670b57cec5SDimitry Andric /// I3: dst = src (copy)
20680b57cec5SDimitry Andric /// (create pred->succ edges I0->I1, I2->I1)
20690b57cec5SDimitry Andric ///
20700b57cec5SDimitry Andric /// 2) Local copy:
20710b57cec5SDimitry Andric /// I0: dst = src (copy)
20720b57cec5SDimitry Andric /// I1:     = dst
20730b57cec5SDimitry Andric /// I2: src = ...
20740b57cec5SDimitry Andric /// I3:     = dst
20750b57cec5SDimitry Andric /// (create pred->succ edges I1->I2, I3->I2)
20760b57cec5SDimitry Andric ///
20770b57cec5SDimitry Andric /// Although the MachineScheduler is currently constrained to single blocks,
20780b57cec5SDimitry Andric /// this algorithm should handle extended blocks. An EBB is a set of
20790b57cec5SDimitry Andric /// contiguously numbered blocks such that the previous block in the EBB is
20800b57cec5SDimitry Andric /// always the single predecessor.
20810b57cec5SDimitry Andric void CopyConstrain::constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG) {
20820b57cec5SDimitry Andric   LiveIntervals *LIS = DAG->getLIS();
20830b57cec5SDimitry Andric   MachineInstr *Copy = CopySU->getInstr();
20840b57cec5SDimitry Andric 
20850b57cec5SDimitry Andric   // Check for pure vreg copies.
20860b57cec5SDimitry Andric   const MachineOperand &SrcOp = Copy->getOperand(1);
20878bcb0991SDimitry Andric   Register SrcReg = SrcOp.getReg();
2088bdd1243dSDimitry Andric   if (!SrcReg.isVirtual() || !SrcOp.readsReg())
20890b57cec5SDimitry Andric     return;
20900b57cec5SDimitry Andric 
20910b57cec5SDimitry Andric   const MachineOperand &DstOp = Copy->getOperand(0);
20928bcb0991SDimitry Andric   Register DstReg = DstOp.getReg();
2093bdd1243dSDimitry Andric   if (!DstReg.isVirtual() || DstOp.isDead())
20940b57cec5SDimitry Andric     return;
20950b57cec5SDimitry Andric 
20960b57cec5SDimitry Andric   // Check if either the dest or source is local. If it's live across a back
20970b57cec5SDimitry Andric   // edge, it's not local. Note that if both vregs are live across the back
20980b57cec5SDimitry Andric   // edge, we cannot successfully contrain the copy without cyclic scheduling.
20990b57cec5SDimitry Andric   // If both the copy's source and dest are local live intervals, then we
21000b57cec5SDimitry Andric   // should treat the dest as the global for the purpose of adding
21010b57cec5SDimitry Andric   // constraints. This adds edges from source's other uses to the copy.
21020b57cec5SDimitry Andric   unsigned LocalReg = SrcReg;
21030b57cec5SDimitry Andric   unsigned GlobalReg = DstReg;
21040b57cec5SDimitry Andric   LiveInterval *LocalLI = &LIS->getInterval(LocalReg);
21050b57cec5SDimitry Andric   if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx)) {
21060b57cec5SDimitry Andric     LocalReg = DstReg;
21070b57cec5SDimitry Andric     GlobalReg = SrcReg;
21080b57cec5SDimitry Andric     LocalLI = &LIS->getInterval(LocalReg);
21090b57cec5SDimitry Andric     if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx))
21100b57cec5SDimitry Andric       return;
21110b57cec5SDimitry Andric   }
21120b57cec5SDimitry Andric   LiveInterval *GlobalLI = &LIS->getInterval(GlobalReg);
21130b57cec5SDimitry Andric 
21140b57cec5SDimitry Andric   // Find the global segment after the start of the local LI.
21150b57cec5SDimitry Andric   LiveInterval::iterator GlobalSegment = GlobalLI->find(LocalLI->beginIndex());
21160b57cec5SDimitry Andric   // If GlobalLI does not overlap LocalLI->start, then a copy directly feeds a
21170b57cec5SDimitry Andric   // local live range. We could create edges from other global uses to the local
21180b57cec5SDimitry Andric   // start, but the coalescer should have already eliminated these cases, so
21190b57cec5SDimitry Andric   // don't bother dealing with it.
21200b57cec5SDimitry Andric   if (GlobalSegment == GlobalLI->end())
21210b57cec5SDimitry Andric     return;
21220b57cec5SDimitry Andric 
21230b57cec5SDimitry Andric   // If GlobalSegment is killed at the LocalLI->start, the call to find()
21240b57cec5SDimitry Andric   // returned the next global segment. But if GlobalSegment overlaps with
21250b57cec5SDimitry Andric   // LocalLI->start, then advance to the next segment. If a hole in GlobalLI
21260b57cec5SDimitry Andric   // exists in LocalLI's vicinity, GlobalSegment will be the end of the hole.
21270b57cec5SDimitry Andric   if (GlobalSegment->contains(LocalLI->beginIndex()))
21280b57cec5SDimitry Andric     ++GlobalSegment;
21290b57cec5SDimitry Andric 
21300b57cec5SDimitry Andric   if (GlobalSegment == GlobalLI->end())
21310b57cec5SDimitry Andric     return;
21320b57cec5SDimitry Andric 
21330b57cec5SDimitry Andric   // Check if GlobalLI contains a hole in the vicinity of LocalLI.
21340b57cec5SDimitry Andric   if (GlobalSegment != GlobalLI->begin()) {
21350b57cec5SDimitry Andric     // Two address defs have no hole.
21360b57cec5SDimitry Andric     if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->end,
21370b57cec5SDimitry Andric                                GlobalSegment->start)) {
21380b57cec5SDimitry Andric       return;
21390b57cec5SDimitry Andric     }
21400b57cec5SDimitry Andric     // If the prior global segment may be defined by the same two-address
21410b57cec5SDimitry Andric     // instruction that also defines LocalLI, then can't make a hole here.
21420b57cec5SDimitry Andric     if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->start,
21430b57cec5SDimitry Andric                                LocalLI->beginIndex())) {
21440b57cec5SDimitry Andric       return;
21450b57cec5SDimitry Andric     }
21460b57cec5SDimitry Andric     // If GlobalLI has a prior segment, it must be live into the EBB. Otherwise
21470b57cec5SDimitry Andric     // it would be a disconnected component in the live range.
21480b57cec5SDimitry Andric     assert(std::prev(GlobalSegment)->start < LocalLI->beginIndex() &&
21490b57cec5SDimitry Andric            "Disconnected LRG within the scheduling region.");
21500b57cec5SDimitry Andric   }
21510b57cec5SDimitry Andric   MachineInstr *GlobalDef = LIS->getInstructionFromIndex(GlobalSegment->start);
21520b57cec5SDimitry Andric   if (!GlobalDef)
21530b57cec5SDimitry Andric     return;
21540b57cec5SDimitry Andric 
21550b57cec5SDimitry Andric   SUnit *GlobalSU = DAG->getSUnit(GlobalDef);
21560b57cec5SDimitry Andric   if (!GlobalSU)
21570b57cec5SDimitry Andric     return;
21580b57cec5SDimitry Andric 
21590b57cec5SDimitry Andric   // GlobalDef is the bottom of the GlobalLI hole. Open the hole by
21600b57cec5SDimitry Andric   // constraining the uses of the last local def to precede GlobalDef.
21610b57cec5SDimitry Andric   SmallVector<SUnit*,8> LocalUses;
21620b57cec5SDimitry Andric   const VNInfo *LastLocalVN = LocalLI->getVNInfoBefore(LocalLI->endIndex());
21630b57cec5SDimitry Andric   MachineInstr *LastLocalDef = LIS->getInstructionFromIndex(LastLocalVN->def);
21640b57cec5SDimitry Andric   SUnit *LastLocalSU = DAG->getSUnit(LastLocalDef);
21650b57cec5SDimitry Andric   for (const SDep &Succ : LastLocalSU->Succs) {
21660b57cec5SDimitry Andric     if (Succ.getKind() != SDep::Data || Succ.getReg() != LocalReg)
21670b57cec5SDimitry Andric       continue;
21680b57cec5SDimitry Andric     if (Succ.getSUnit() == GlobalSU)
21690b57cec5SDimitry Andric       continue;
21700b57cec5SDimitry Andric     if (!DAG->canAddEdge(GlobalSU, Succ.getSUnit()))
21710b57cec5SDimitry Andric       return;
21720b57cec5SDimitry Andric     LocalUses.push_back(Succ.getSUnit());
21730b57cec5SDimitry Andric   }
21740b57cec5SDimitry Andric   // Open the top of the GlobalLI hole by constraining any earlier global uses
21750b57cec5SDimitry Andric   // to precede the start of LocalLI.
21760b57cec5SDimitry Andric   SmallVector<SUnit*,8> GlobalUses;
21770b57cec5SDimitry Andric   MachineInstr *FirstLocalDef =
21780b57cec5SDimitry Andric     LIS->getInstructionFromIndex(LocalLI->beginIndex());
21790b57cec5SDimitry Andric   SUnit *FirstLocalSU = DAG->getSUnit(FirstLocalDef);
21800b57cec5SDimitry Andric   for (const SDep &Pred : GlobalSU->Preds) {
21810b57cec5SDimitry Andric     if (Pred.getKind() != SDep::Anti || Pred.getReg() != GlobalReg)
21820b57cec5SDimitry Andric       continue;
21830b57cec5SDimitry Andric     if (Pred.getSUnit() == FirstLocalSU)
21840b57cec5SDimitry Andric       continue;
21850b57cec5SDimitry Andric     if (!DAG->canAddEdge(FirstLocalSU, Pred.getSUnit()))
21860b57cec5SDimitry Andric       return;
21870b57cec5SDimitry Andric     GlobalUses.push_back(Pred.getSUnit());
21880b57cec5SDimitry Andric   }
21890b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Constraining copy SU(" << CopySU->NodeNum << ")\n");
21900b57cec5SDimitry Andric   // Add the weak edges.
2191fe6060f1SDimitry Andric   for (SUnit *LU : LocalUses) {
2192fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "  Local use SU(" << LU->NodeNum << ") -> SU("
21930b57cec5SDimitry Andric                       << GlobalSU->NodeNum << ")\n");
2194fe6060f1SDimitry Andric     DAG->addEdge(GlobalSU, SDep(LU, SDep::Weak));
21950b57cec5SDimitry Andric   }
2196fe6060f1SDimitry Andric   for (SUnit *GU : GlobalUses) {
2197fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "  Global use SU(" << GU->NodeNum << ") -> SU("
21980b57cec5SDimitry Andric                       << FirstLocalSU->NodeNum << ")\n");
2199fe6060f1SDimitry Andric     DAG->addEdge(FirstLocalSU, SDep(GU, SDep::Weak));
22000b57cec5SDimitry Andric   }
22010b57cec5SDimitry Andric }
22020b57cec5SDimitry Andric 
22030b57cec5SDimitry Andric /// Callback from DAG postProcessing to create weak edges to encourage
22040b57cec5SDimitry Andric /// copy elimination.
22050b57cec5SDimitry Andric void CopyConstrain::apply(ScheduleDAGInstrs *DAGInstrs) {
22060b57cec5SDimitry Andric   ScheduleDAGMI *DAG = static_cast<ScheduleDAGMI*>(DAGInstrs);
22070b57cec5SDimitry Andric   assert(DAG->hasVRegLiveness() && "Expect VRegs with LiveIntervals");
22080b57cec5SDimitry Andric 
22090b57cec5SDimitry Andric   MachineBasicBlock::iterator FirstPos = nextIfDebug(DAG->begin(), DAG->end());
22100b57cec5SDimitry Andric   if (FirstPos == DAG->end())
22110b57cec5SDimitry Andric     return;
22120b57cec5SDimitry Andric   RegionBeginIdx = DAG->getLIS()->getInstructionIndex(*FirstPos);
22130b57cec5SDimitry Andric   RegionEndIdx = DAG->getLIS()->getInstructionIndex(
22140b57cec5SDimitry Andric       *priorNonDebug(DAG->end(), DAG->begin()));
22150b57cec5SDimitry Andric 
22160b57cec5SDimitry Andric   for (SUnit &SU : DAG->SUnits) {
22170b57cec5SDimitry Andric     if (!SU.getInstr()->isCopy())
22180b57cec5SDimitry Andric       continue;
22190b57cec5SDimitry Andric 
22200b57cec5SDimitry Andric     constrainLocalCopy(&SU, static_cast<ScheduleDAGMILive*>(DAG));
22210b57cec5SDimitry Andric   }
22220b57cec5SDimitry Andric }
22230b57cec5SDimitry Andric 
22240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
22250b57cec5SDimitry Andric // MachineSchedStrategy helpers used by GenericScheduler, GenericPostScheduler
22260b57cec5SDimitry Andric // and possibly other custom schedulers.
22270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
22280b57cec5SDimitry Andric 
22290b57cec5SDimitry Andric static const unsigned InvalidCycle = ~0U;
22300b57cec5SDimitry Andric 
22310b57cec5SDimitry Andric SchedBoundary::~SchedBoundary() { delete HazardRec; }
22320b57cec5SDimitry Andric 
22330b57cec5SDimitry Andric /// Given a Count of resource usage and a Latency value, return true if a
22340b57cec5SDimitry Andric /// SchedBoundary becomes resource limited.
22350b57cec5SDimitry Andric /// If we are checking after scheduling a node, we should return true when
22360b57cec5SDimitry Andric /// we just reach the resource limit.
22370b57cec5SDimitry Andric static bool checkResourceLimit(unsigned LFactor, unsigned Count,
22380b57cec5SDimitry Andric                                unsigned Latency, bool AfterSchedNode) {
22390b57cec5SDimitry Andric   int ResCntFactor = (int)(Count - (Latency * LFactor));
22400b57cec5SDimitry Andric   if (AfterSchedNode)
22410b57cec5SDimitry Andric     return ResCntFactor >= (int)LFactor;
22420b57cec5SDimitry Andric   else
22430b57cec5SDimitry Andric     return ResCntFactor > (int)LFactor;
22440b57cec5SDimitry Andric }
22450b57cec5SDimitry Andric 
22460b57cec5SDimitry Andric void SchedBoundary::reset() {
22470b57cec5SDimitry Andric   // A new HazardRec is created for each DAG and owned by SchedBoundary.
22480b57cec5SDimitry Andric   // Destroying and reconstructing it is very expensive though. So keep
22490b57cec5SDimitry Andric   // invalid, placeholder HazardRecs.
22500b57cec5SDimitry Andric   if (HazardRec && HazardRec->isEnabled()) {
22510b57cec5SDimitry Andric     delete HazardRec;
22520b57cec5SDimitry Andric     HazardRec = nullptr;
22530b57cec5SDimitry Andric   }
22540b57cec5SDimitry Andric   Available.clear();
22550b57cec5SDimitry Andric   Pending.clear();
22560b57cec5SDimitry Andric   CheckPending = false;
22570b57cec5SDimitry Andric   CurrCycle = 0;
22580b57cec5SDimitry Andric   CurrMOps = 0;
22590b57cec5SDimitry Andric   MinReadyCycle = std::numeric_limits<unsigned>::max();
22600b57cec5SDimitry Andric   ExpectedLatency = 0;
22610b57cec5SDimitry Andric   DependentLatency = 0;
22620b57cec5SDimitry Andric   RetiredMOps = 0;
22630b57cec5SDimitry Andric   MaxExecutedResCount = 0;
22640b57cec5SDimitry Andric   ZoneCritResIdx = 0;
22650b57cec5SDimitry Andric   IsResourceLimited = false;
22660b57cec5SDimitry Andric   ReservedCycles.clear();
226706c3fb27SDimitry Andric   ReservedResourceSegments.clear();
22680b57cec5SDimitry Andric   ReservedCyclesIndex.clear();
2269fe6060f1SDimitry Andric   ResourceGroupSubUnitMasks.clear();
227081ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS
22710b57cec5SDimitry Andric   // Track the maximum number of stall cycles that could arise either from the
22720b57cec5SDimitry Andric   // latency of a DAG edge or the number of cycles that a processor resource is
22730b57cec5SDimitry Andric   // reserved (SchedBoundary::ReservedCycles).
22740b57cec5SDimitry Andric   MaxObservedStall = 0;
22750b57cec5SDimitry Andric #endif
22760b57cec5SDimitry Andric   // Reserve a zero-count for invalid CritResIdx.
22770b57cec5SDimitry Andric   ExecutedResCounts.resize(1);
22780b57cec5SDimitry Andric   assert(!ExecutedResCounts[0] && "nonzero count for bad resource");
22790b57cec5SDimitry Andric }
22800b57cec5SDimitry Andric 
22810b57cec5SDimitry Andric void SchedRemainder::
22820b57cec5SDimitry Andric init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel) {
22830b57cec5SDimitry Andric   reset();
22840b57cec5SDimitry Andric   if (!SchedModel->hasInstrSchedModel())
22850b57cec5SDimitry Andric     return;
22860b57cec5SDimitry Andric   RemainingCounts.resize(SchedModel->getNumProcResourceKinds());
22870b57cec5SDimitry Andric   for (SUnit &SU : DAG->SUnits) {
22880b57cec5SDimitry Andric     const MCSchedClassDesc *SC = DAG->getSchedClass(&SU);
22890b57cec5SDimitry Andric     RemIssueCount += SchedModel->getNumMicroOps(SU.getInstr(), SC)
22900b57cec5SDimitry Andric       * SchedModel->getMicroOpFactor();
22910b57cec5SDimitry Andric     for (TargetSchedModel::ProcResIter
22920b57cec5SDimitry Andric            PI = SchedModel->getWriteProcResBegin(SC),
22930b57cec5SDimitry Andric            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
22940b57cec5SDimitry Andric       unsigned PIdx = PI->ProcResourceIdx;
22950b57cec5SDimitry Andric       unsigned Factor = SchedModel->getResourceFactor(PIdx);
22965f757f3fSDimitry Andric       assert(PI->ReleaseAtCycle >= PI->AcquireAtCycle);
22975f757f3fSDimitry Andric       RemainingCounts[PIdx] +=
22985f757f3fSDimitry Andric           (Factor * (PI->ReleaseAtCycle - PI->AcquireAtCycle));
22990b57cec5SDimitry Andric     }
23000b57cec5SDimitry Andric   }
23010b57cec5SDimitry Andric }
23020b57cec5SDimitry Andric 
23030b57cec5SDimitry Andric void SchedBoundary::
23040b57cec5SDimitry Andric init(ScheduleDAGMI *dag, const TargetSchedModel *smodel, SchedRemainder *rem) {
23050b57cec5SDimitry Andric   reset();
23060b57cec5SDimitry Andric   DAG = dag;
23070b57cec5SDimitry Andric   SchedModel = smodel;
23080b57cec5SDimitry Andric   Rem = rem;
23090b57cec5SDimitry Andric   if (SchedModel->hasInstrSchedModel()) {
23100b57cec5SDimitry Andric     unsigned ResourceCount = SchedModel->getNumProcResourceKinds();
23110b57cec5SDimitry Andric     ReservedCyclesIndex.resize(ResourceCount);
23120b57cec5SDimitry Andric     ExecutedResCounts.resize(ResourceCount);
2313fe6060f1SDimitry Andric     ResourceGroupSubUnitMasks.resize(ResourceCount, APInt(ResourceCount, 0));
23140b57cec5SDimitry Andric     unsigned NumUnits = 0;
23150b57cec5SDimitry Andric 
23160b57cec5SDimitry Andric     for (unsigned i = 0; i < ResourceCount; ++i) {
23170b57cec5SDimitry Andric       ReservedCyclesIndex[i] = NumUnits;
23180b57cec5SDimitry Andric       NumUnits += SchedModel->getProcResource(i)->NumUnits;
2319fe6060f1SDimitry Andric       if (isUnbufferedGroup(i)) {
2320fe6060f1SDimitry Andric         auto SubUnits = SchedModel->getProcResource(i)->SubUnitsIdxBegin;
2321fe6060f1SDimitry Andric         for (unsigned U = 0, UE = SchedModel->getProcResource(i)->NumUnits;
2322fe6060f1SDimitry Andric              U != UE; ++U)
2323fe6060f1SDimitry Andric           ResourceGroupSubUnitMasks[i].setBit(SubUnits[U]);
2324fe6060f1SDimitry Andric       }
23250b57cec5SDimitry Andric     }
23260b57cec5SDimitry Andric 
23270b57cec5SDimitry Andric     ReservedCycles.resize(NumUnits, InvalidCycle);
23280b57cec5SDimitry Andric   }
23290b57cec5SDimitry Andric }
23300b57cec5SDimitry Andric 
23310b57cec5SDimitry Andric /// Compute the stall cycles based on this SUnit's ready time. Heuristics treat
23320b57cec5SDimitry Andric /// these "soft stalls" differently than the hard stall cycles based on CPU
23330b57cec5SDimitry Andric /// resources and computed by checkHazard(). A fully in-order model
23340b57cec5SDimitry Andric /// (MicroOpBufferSize==0) will not make use of this since instructions are not
23350b57cec5SDimitry Andric /// available for scheduling until they are ready. However, a weaker in-order
23360b57cec5SDimitry Andric /// model may use this for heuristics. For example, if a processor has in-order
23370b57cec5SDimitry Andric /// behavior when reading certain resources, this may come into play.
23380b57cec5SDimitry Andric unsigned SchedBoundary::getLatencyStallCycles(SUnit *SU) {
23390b57cec5SDimitry Andric   if (!SU->isUnbuffered)
23400b57cec5SDimitry Andric     return 0;
23410b57cec5SDimitry Andric 
23420b57cec5SDimitry Andric   unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle);
23430b57cec5SDimitry Andric   if (ReadyCycle > CurrCycle)
23440b57cec5SDimitry Andric     return ReadyCycle - CurrCycle;
23450b57cec5SDimitry Andric   return 0;
23460b57cec5SDimitry Andric }
23470b57cec5SDimitry Andric 
23480b57cec5SDimitry Andric /// Compute the next cycle at which the given processor resource unit
23490b57cec5SDimitry Andric /// can be scheduled.
23500b57cec5SDimitry Andric unsigned SchedBoundary::getNextResourceCycleByInstance(unsigned InstanceIdx,
23515f757f3fSDimitry Andric                                                        unsigned ReleaseAtCycle,
23525f757f3fSDimitry Andric                                                        unsigned AcquireAtCycle) {
235306c3fb27SDimitry Andric   if (SchedModel && SchedModel->enableIntervals()) {
235406c3fb27SDimitry Andric     if (isTop())
235506c3fb27SDimitry Andric       return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromTop(
23565f757f3fSDimitry Andric           CurrCycle, AcquireAtCycle, ReleaseAtCycle);
235706c3fb27SDimitry Andric 
235806c3fb27SDimitry Andric     return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromBottom(
23595f757f3fSDimitry Andric         CurrCycle, AcquireAtCycle, ReleaseAtCycle);
236006c3fb27SDimitry Andric   }
236106c3fb27SDimitry Andric 
23620b57cec5SDimitry Andric   unsigned NextUnreserved = ReservedCycles[InstanceIdx];
23630b57cec5SDimitry Andric   // If this resource has never been used, always return cycle zero.
23640b57cec5SDimitry Andric   if (NextUnreserved == InvalidCycle)
236506c3fb27SDimitry Andric     return CurrCycle;
23660b57cec5SDimitry Andric   // For bottom-up scheduling add the cycles needed for the current operation.
23670b57cec5SDimitry Andric   if (!isTop())
23685f757f3fSDimitry Andric     NextUnreserved = std::max(CurrCycle, NextUnreserved + ReleaseAtCycle);
23690b57cec5SDimitry Andric   return NextUnreserved;
23700b57cec5SDimitry Andric }
23710b57cec5SDimitry Andric 
23720b57cec5SDimitry Andric /// Compute the next cycle at which the given processor resource can be
23730b57cec5SDimitry Andric /// scheduled.  Returns the next cycle and the index of the processor resource
23740b57cec5SDimitry Andric /// instance in the reserved cycles vector.
23750b57cec5SDimitry Andric std::pair<unsigned, unsigned>
2376fe6060f1SDimitry Andric SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx,
23775f757f3fSDimitry Andric                                     unsigned ReleaseAtCycle,
23785f757f3fSDimitry Andric                                     unsigned AcquireAtCycle) {
237906c3fb27SDimitry Andric   if (MischedDetailResourceBooking) {
238006c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "  Resource booking (@" << CurrCycle << "c): \n");
238106c3fb27SDimitry Andric     LLVM_DEBUG(dumpReservedCycles());
238206c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "  getNextResourceCycle (@" << CurrCycle << "c): \n");
238306c3fb27SDimitry Andric   }
23840b57cec5SDimitry Andric   unsigned MinNextUnreserved = InvalidCycle;
23850b57cec5SDimitry Andric   unsigned InstanceIdx = 0;
23860b57cec5SDimitry Andric   unsigned StartIndex = ReservedCyclesIndex[PIdx];
23870b57cec5SDimitry Andric   unsigned NumberOfInstances = SchedModel->getProcResource(PIdx)->NumUnits;
23880b57cec5SDimitry Andric   assert(NumberOfInstances > 0 &&
23890b57cec5SDimitry Andric          "Cannot have zero instances of a ProcResource");
23900b57cec5SDimitry Andric 
2391fe6060f1SDimitry Andric   if (isUnbufferedGroup(PIdx)) {
23925f757f3fSDimitry Andric     // If any subunits are used by the instruction, report that the
23935f757f3fSDimitry Andric     // subunits of the resource group are available at the first cycle
23945f757f3fSDimitry Andric     // in which the unit is available, effectively removing the group
23955f757f3fSDimitry Andric     // record from hazarding and basing the hazarding decisions on the
23965f757f3fSDimitry Andric     // subunit records. Otherwise, choose the first available instance
23975f757f3fSDimitry Andric     // from among the subunits.  Specifications which assign cycles to
23985f757f3fSDimitry Andric     // both the subunits and the group or which use an unbuffered
23995f757f3fSDimitry Andric     // group with buffered subunits will appear to schedule
24005f757f3fSDimitry Andric     // strangely. In the first case, the additional cycles for the
24015f757f3fSDimitry Andric     // group will be ignored.  In the second, the group will be
24025f757f3fSDimitry Andric     // ignored entirely.
2403fe6060f1SDimitry Andric     for (const MCWriteProcResEntry &PE :
2404fe6060f1SDimitry Andric          make_range(SchedModel->getWriteProcResBegin(SC),
2405fe6060f1SDimitry Andric                     SchedModel->getWriteProcResEnd(SC)))
2406fe6060f1SDimitry Andric       if (ResourceGroupSubUnitMasks[PIdx][PE.ProcResourceIdx])
24075f757f3fSDimitry Andric         return std::make_pair(getNextResourceCycleByInstance(
24085f757f3fSDimitry Andric                                   StartIndex, ReleaseAtCycle, AcquireAtCycle),
24095f757f3fSDimitry Andric                               StartIndex);
2410fe6060f1SDimitry Andric 
2411fe6060f1SDimitry Andric     auto SubUnits = SchedModel->getProcResource(PIdx)->SubUnitsIdxBegin;
2412fe6060f1SDimitry Andric     for (unsigned I = 0, End = NumberOfInstances; I < End; ++I) {
2413fe6060f1SDimitry Andric       unsigned NextUnreserved, NextInstanceIdx;
2414fe6060f1SDimitry Andric       std::tie(NextUnreserved, NextInstanceIdx) =
24155f757f3fSDimitry Andric           getNextResourceCycle(SC, SubUnits[I], ReleaseAtCycle, AcquireAtCycle);
2416fe6060f1SDimitry Andric       if (MinNextUnreserved > NextUnreserved) {
2417fe6060f1SDimitry Andric         InstanceIdx = NextInstanceIdx;
2418fe6060f1SDimitry Andric         MinNextUnreserved = NextUnreserved;
2419fe6060f1SDimitry Andric       }
2420fe6060f1SDimitry Andric     }
2421fe6060f1SDimitry Andric     return std::make_pair(MinNextUnreserved, InstanceIdx);
2422fe6060f1SDimitry Andric   }
2423fe6060f1SDimitry Andric 
24240b57cec5SDimitry Andric   for (unsigned I = StartIndex, End = StartIndex + NumberOfInstances; I < End;
24250b57cec5SDimitry Andric        ++I) {
242606c3fb27SDimitry Andric     unsigned NextUnreserved =
24275f757f3fSDimitry Andric         getNextResourceCycleByInstance(I, ReleaseAtCycle, AcquireAtCycle);
242806c3fb27SDimitry Andric     if (MischedDetailResourceBooking)
242906c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "    Instance " << I - StartIndex << " available @"
243006c3fb27SDimitry Andric                         << NextUnreserved << "c\n");
24310b57cec5SDimitry Andric     if (MinNextUnreserved > NextUnreserved) {
24320b57cec5SDimitry Andric       InstanceIdx = I;
24330b57cec5SDimitry Andric       MinNextUnreserved = NextUnreserved;
24340b57cec5SDimitry Andric     }
24350b57cec5SDimitry Andric   }
243606c3fb27SDimitry Andric   if (MischedDetailResourceBooking)
243706c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "    selecting " << SchedModel->getResourceName(PIdx)
243806c3fb27SDimitry Andric                       << "[" << InstanceIdx - StartIndex << "]"
243906c3fb27SDimitry Andric                       << " available @" << MinNextUnreserved << "c"
244006c3fb27SDimitry Andric                       << "\n");
24410b57cec5SDimitry Andric   return std::make_pair(MinNextUnreserved, InstanceIdx);
24420b57cec5SDimitry Andric }
24430b57cec5SDimitry Andric 
24440b57cec5SDimitry Andric /// Does this SU have a hazard within the current instruction group.
24450b57cec5SDimitry Andric ///
24460b57cec5SDimitry Andric /// The scheduler supports two modes of hazard recognition. The first is the
24470b57cec5SDimitry Andric /// ScheduleHazardRecognizer API. It is a fully general hazard recognizer that
24480b57cec5SDimitry Andric /// supports highly complicated in-order reservation tables
24490b57cec5SDimitry Andric /// (ScoreboardHazardRecognizer) and arbitrary target-specific logic.
24500b57cec5SDimitry Andric ///
24510b57cec5SDimitry Andric /// The second is a streamlined mechanism that checks for hazards based on
24520b57cec5SDimitry Andric /// simple counters that the scheduler itself maintains. It explicitly checks
24530b57cec5SDimitry Andric /// for instruction dispatch limitations, including the number of micro-ops that
24540b57cec5SDimitry Andric /// can dispatch per cycle.
24550b57cec5SDimitry Andric ///
24560b57cec5SDimitry Andric /// TODO: Also check whether the SU must start a new group.
24570b57cec5SDimitry Andric bool SchedBoundary::checkHazard(SUnit *SU) {
24580b57cec5SDimitry Andric   if (HazardRec->isEnabled()
24590b57cec5SDimitry Andric       && HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard) {
24600b57cec5SDimitry Andric     return true;
24610b57cec5SDimitry Andric   }
24620b57cec5SDimitry Andric 
24630b57cec5SDimitry Andric   unsigned uops = SchedModel->getNumMicroOps(SU->getInstr());
24640b57cec5SDimitry Andric   if ((CurrMOps > 0) && (CurrMOps + uops > SchedModel->getIssueWidth())) {
24650b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  SU(" << SU->NodeNum << ") uops="
24660b57cec5SDimitry Andric                       << SchedModel->getNumMicroOps(SU->getInstr()) << '\n');
24670b57cec5SDimitry Andric     return true;
24680b57cec5SDimitry Andric   }
24690b57cec5SDimitry Andric 
24700b57cec5SDimitry Andric   if (CurrMOps > 0 &&
24710b57cec5SDimitry Andric       ((isTop() && SchedModel->mustBeginGroup(SU->getInstr())) ||
24720b57cec5SDimitry Andric        (!isTop() && SchedModel->mustEndGroup(SU->getInstr())))) {
24730b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  hazard: SU(" << SU->NodeNum << ") must "
24740b57cec5SDimitry Andric                       << (isTop() ? "begin" : "end") << " group\n");
24750b57cec5SDimitry Andric     return true;
24760b57cec5SDimitry Andric   }
24770b57cec5SDimitry Andric 
24780b57cec5SDimitry Andric   if (SchedModel->hasInstrSchedModel() && SU->hasReservedResource) {
24790b57cec5SDimitry Andric     const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
24800b57cec5SDimitry Andric     for (const MCWriteProcResEntry &PE :
24810b57cec5SDimitry Andric           make_range(SchedModel->getWriteProcResBegin(SC),
24820b57cec5SDimitry Andric                      SchedModel->getWriteProcResEnd(SC))) {
24830b57cec5SDimitry Andric       unsigned ResIdx = PE.ProcResourceIdx;
24845f757f3fSDimitry Andric       unsigned ReleaseAtCycle = PE.ReleaseAtCycle;
24855f757f3fSDimitry Andric       unsigned AcquireAtCycle = PE.AcquireAtCycle;
24860b57cec5SDimitry Andric       unsigned NRCycle, InstanceIdx;
248706c3fb27SDimitry Andric       std::tie(NRCycle, InstanceIdx) =
24885f757f3fSDimitry Andric           getNextResourceCycle(SC, ResIdx, ReleaseAtCycle, AcquireAtCycle);
24890b57cec5SDimitry Andric       if (NRCycle > CurrCycle) {
249081ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS
24915f757f3fSDimitry Andric         MaxObservedStall = std::max(ReleaseAtCycle, MaxObservedStall);
24920b57cec5SDimitry Andric #endif
24930b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "  SU(" << SU->NodeNum << ") "
24940b57cec5SDimitry Andric                           << SchedModel->getResourceName(ResIdx)
24950b57cec5SDimitry Andric                           << '[' << InstanceIdx - ReservedCyclesIndex[ResIdx]  << ']'
24960b57cec5SDimitry Andric                           << "=" << NRCycle << "c\n");
24970b57cec5SDimitry Andric         return true;
24980b57cec5SDimitry Andric       }
24990b57cec5SDimitry Andric     }
25000b57cec5SDimitry Andric   }
25010b57cec5SDimitry Andric   return false;
25020b57cec5SDimitry Andric }
25030b57cec5SDimitry Andric 
25040b57cec5SDimitry Andric // Find the unscheduled node in ReadySUs with the highest latency.
25050b57cec5SDimitry Andric unsigned SchedBoundary::
25060b57cec5SDimitry Andric findMaxLatency(ArrayRef<SUnit*> ReadySUs) {
25070b57cec5SDimitry Andric   SUnit *LateSU = nullptr;
25080b57cec5SDimitry Andric   unsigned RemLatency = 0;
25090b57cec5SDimitry Andric   for (SUnit *SU : ReadySUs) {
25100b57cec5SDimitry Andric     unsigned L = getUnscheduledLatency(SU);
25110b57cec5SDimitry Andric     if (L > RemLatency) {
25120b57cec5SDimitry Andric       RemLatency = L;
25130b57cec5SDimitry Andric       LateSU = SU;
25140b57cec5SDimitry Andric     }
25150b57cec5SDimitry Andric   }
25160b57cec5SDimitry Andric   if (LateSU) {
25170b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << Available.getName() << " RemLatency SU("
25180b57cec5SDimitry Andric                       << LateSU->NodeNum << ") " << RemLatency << "c\n");
25190b57cec5SDimitry Andric   }
25200b57cec5SDimitry Andric   return RemLatency;
25210b57cec5SDimitry Andric }
25220b57cec5SDimitry Andric 
25230b57cec5SDimitry Andric // Count resources in this zone and the remaining unscheduled
25240b57cec5SDimitry Andric // instruction. Return the max count, scaled. Set OtherCritIdx to the critical
25250b57cec5SDimitry Andric // resource index, or zero if the zone is issue limited.
25260b57cec5SDimitry Andric unsigned SchedBoundary::
25270b57cec5SDimitry Andric getOtherResourceCount(unsigned &OtherCritIdx) {
25280b57cec5SDimitry Andric   OtherCritIdx = 0;
25290b57cec5SDimitry Andric   if (!SchedModel->hasInstrSchedModel())
25300b57cec5SDimitry Andric     return 0;
25310b57cec5SDimitry Andric 
25320b57cec5SDimitry Andric   unsigned OtherCritCount = Rem->RemIssueCount
25330b57cec5SDimitry Andric     + (RetiredMOps * SchedModel->getMicroOpFactor());
25340b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "  " << Available.getName() << " + Remain MOps: "
25350b57cec5SDimitry Andric                     << OtherCritCount / SchedModel->getMicroOpFactor() << '\n');
25360b57cec5SDimitry Andric   for (unsigned PIdx = 1, PEnd = SchedModel->getNumProcResourceKinds();
25370b57cec5SDimitry Andric        PIdx != PEnd; ++PIdx) {
25380b57cec5SDimitry Andric     unsigned OtherCount = getResourceCount(PIdx) + Rem->RemainingCounts[PIdx];
25390b57cec5SDimitry Andric     if (OtherCount > OtherCritCount) {
25400b57cec5SDimitry Andric       OtherCritCount = OtherCount;
25410b57cec5SDimitry Andric       OtherCritIdx = PIdx;
25420b57cec5SDimitry Andric     }
25430b57cec5SDimitry Andric   }
25440b57cec5SDimitry Andric   if (OtherCritIdx) {
25450b57cec5SDimitry Andric     LLVM_DEBUG(
25460b57cec5SDimitry Andric         dbgs() << "  " << Available.getName() << " + Remain CritRes: "
25470b57cec5SDimitry Andric                << OtherCritCount / SchedModel->getResourceFactor(OtherCritIdx)
25480b57cec5SDimitry Andric                << " " << SchedModel->getResourceName(OtherCritIdx) << "\n");
25490b57cec5SDimitry Andric   }
25500b57cec5SDimitry Andric   return OtherCritCount;
25510b57cec5SDimitry Andric }
25520b57cec5SDimitry Andric 
2553480093f4SDimitry Andric void SchedBoundary::releaseNode(SUnit *SU, unsigned ReadyCycle, bool InPQueue,
2554480093f4SDimitry Andric                                 unsigned Idx) {
25550b57cec5SDimitry Andric   assert(SU->getInstr() && "Scheduled SUnit must have instr");
25560b57cec5SDimitry Andric 
255781ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS
25580b57cec5SDimitry Andric   // ReadyCycle was been bumped up to the CurrCycle when this node was
25590b57cec5SDimitry Andric   // scheduled, but CurrCycle may have been eagerly advanced immediately after
25600b57cec5SDimitry Andric   // scheduling, so may now be greater than ReadyCycle.
25610b57cec5SDimitry Andric   if (ReadyCycle > CurrCycle)
25620b57cec5SDimitry Andric     MaxObservedStall = std::max(ReadyCycle - CurrCycle, MaxObservedStall);
25630b57cec5SDimitry Andric #endif
25640b57cec5SDimitry Andric 
25650b57cec5SDimitry Andric   if (ReadyCycle < MinReadyCycle)
25660b57cec5SDimitry Andric     MinReadyCycle = ReadyCycle;
25670b57cec5SDimitry Andric 
25680b57cec5SDimitry Andric   // Check for interlocks first. For the purpose of other heuristics, an
25690b57cec5SDimitry Andric   // instruction that cannot issue appears as if it's not in the ReadyQueue.
25700b57cec5SDimitry Andric   bool IsBuffered = SchedModel->getMicroOpBufferSize() != 0;
2571480093f4SDimitry Andric   bool HazardDetected = (!IsBuffered && ReadyCycle > CurrCycle) ||
2572480093f4SDimitry Andric                         checkHazard(SU) || (Available.size() >= ReadyListLimit);
2573480093f4SDimitry Andric 
2574480093f4SDimitry Andric   if (!HazardDetected) {
25750b57cec5SDimitry Andric     Available.push(SU);
2576480093f4SDimitry Andric 
2577480093f4SDimitry Andric     if (InPQueue)
2578480093f4SDimitry Andric       Pending.remove(Pending.begin() + Idx);
2579480093f4SDimitry Andric     return;
2580480093f4SDimitry Andric   }
2581480093f4SDimitry Andric 
2582480093f4SDimitry Andric   if (!InPQueue)
2583480093f4SDimitry Andric     Pending.push(SU);
25840b57cec5SDimitry Andric }
25850b57cec5SDimitry Andric 
25860b57cec5SDimitry Andric /// Move the boundary of scheduled code by one cycle.
25870b57cec5SDimitry Andric void SchedBoundary::bumpCycle(unsigned NextCycle) {
25880b57cec5SDimitry Andric   if (SchedModel->getMicroOpBufferSize() == 0) {
25890b57cec5SDimitry Andric     assert(MinReadyCycle < std::numeric_limits<unsigned>::max() &&
25900b57cec5SDimitry Andric            "MinReadyCycle uninitialized");
25910b57cec5SDimitry Andric     if (MinReadyCycle > NextCycle)
25920b57cec5SDimitry Andric       NextCycle = MinReadyCycle;
25930b57cec5SDimitry Andric   }
25940b57cec5SDimitry Andric   // Update the current micro-ops, which will issue in the next cycle.
25950b57cec5SDimitry Andric   unsigned DecMOps = SchedModel->getIssueWidth() * (NextCycle - CurrCycle);
25960b57cec5SDimitry Andric   CurrMOps = (CurrMOps <= DecMOps) ? 0 : CurrMOps - DecMOps;
25970b57cec5SDimitry Andric 
25980b57cec5SDimitry Andric   // Decrement DependentLatency based on the next cycle.
25990b57cec5SDimitry Andric   if ((NextCycle - CurrCycle) > DependentLatency)
26000b57cec5SDimitry Andric     DependentLatency = 0;
26010b57cec5SDimitry Andric   else
26020b57cec5SDimitry Andric     DependentLatency -= (NextCycle - CurrCycle);
26030b57cec5SDimitry Andric 
26040b57cec5SDimitry Andric   if (!HazardRec->isEnabled()) {
26050b57cec5SDimitry Andric     // Bypass HazardRec virtual calls.
26060b57cec5SDimitry Andric     CurrCycle = NextCycle;
26070b57cec5SDimitry Andric   } else {
26080b57cec5SDimitry Andric     // Bypass getHazardType calls in case of long latency.
26090b57cec5SDimitry Andric     for (; CurrCycle != NextCycle; ++CurrCycle) {
26100b57cec5SDimitry Andric       if (isTop())
26110b57cec5SDimitry Andric         HazardRec->AdvanceCycle();
26120b57cec5SDimitry Andric       else
26130b57cec5SDimitry Andric         HazardRec->RecedeCycle();
26140b57cec5SDimitry Andric     }
26150b57cec5SDimitry Andric   }
26160b57cec5SDimitry Andric   CheckPending = true;
26170b57cec5SDimitry Andric   IsResourceLimited =
26180b57cec5SDimitry Andric       checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(),
26190b57cec5SDimitry Andric                          getScheduledLatency(), true);
26200b57cec5SDimitry Andric 
26210b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Cycle: " << CurrCycle << ' ' << Available.getName()
26220b57cec5SDimitry Andric                     << '\n');
26230b57cec5SDimitry Andric }
26240b57cec5SDimitry Andric 
26250b57cec5SDimitry Andric void SchedBoundary::incExecutedResources(unsigned PIdx, unsigned Count) {
26260b57cec5SDimitry Andric   ExecutedResCounts[PIdx] += Count;
26270b57cec5SDimitry Andric   if (ExecutedResCounts[PIdx] > MaxExecutedResCount)
26280b57cec5SDimitry Andric     MaxExecutedResCount = ExecutedResCounts[PIdx];
26290b57cec5SDimitry Andric }
26300b57cec5SDimitry Andric 
26310b57cec5SDimitry Andric /// Add the given processor resource to this scheduled zone.
26320b57cec5SDimitry Andric ///
26335f757f3fSDimitry Andric /// \param ReleaseAtCycle indicates the number of consecutive (non-pipelined)
26345f757f3fSDimitry Andric /// cycles during which this resource is released.
26355f757f3fSDimitry Andric ///
26365f757f3fSDimitry Andric /// \param AcquireAtCycle indicates the number of consecutive (non-pipelined)
26375f757f3fSDimitry Andric /// cycles at which the resource is aquired after issue (assuming no stalls).
26380b57cec5SDimitry Andric ///
26390b57cec5SDimitry Andric /// \return the next cycle at which the instruction may execute without
26400b57cec5SDimitry Andric /// oversubscribing resources.
2641fe6060f1SDimitry Andric unsigned SchedBoundary::countResource(const MCSchedClassDesc *SC, unsigned PIdx,
26425f757f3fSDimitry Andric                                       unsigned ReleaseAtCycle,
26435f757f3fSDimitry Andric                                       unsigned NextCycle,
26445f757f3fSDimitry Andric                                       unsigned AcquireAtCycle) {
26450b57cec5SDimitry Andric   unsigned Factor = SchedModel->getResourceFactor(PIdx);
26465f757f3fSDimitry Andric   unsigned Count = Factor * (ReleaseAtCycle- AcquireAtCycle);
26470b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "  " << SchedModel->getResourceName(PIdx) << " +"
26485f757f3fSDimitry Andric                     << ReleaseAtCycle << "x" << Factor << "u\n");
26490b57cec5SDimitry Andric 
26500b57cec5SDimitry Andric   // Update Executed resources counts.
26510b57cec5SDimitry Andric   incExecutedResources(PIdx, Count);
26520b57cec5SDimitry Andric   assert(Rem->RemainingCounts[PIdx] >= Count && "resource double counted");
26530b57cec5SDimitry Andric   Rem->RemainingCounts[PIdx] -= Count;
26540b57cec5SDimitry Andric 
26550b57cec5SDimitry Andric   // Check if this resource exceeds the current critical resource. If so, it
26560b57cec5SDimitry Andric   // becomes the critical resource.
26570b57cec5SDimitry Andric   if (ZoneCritResIdx != PIdx && (getResourceCount(PIdx) > getCriticalCount())) {
26580b57cec5SDimitry Andric     ZoneCritResIdx = PIdx;
26590b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  *** Critical resource "
26600b57cec5SDimitry Andric                       << SchedModel->getResourceName(PIdx) << ": "
26610b57cec5SDimitry Andric                       << getResourceCount(PIdx) / SchedModel->getLatencyFactor()
26620b57cec5SDimitry Andric                       << "c\n");
26630b57cec5SDimitry Andric   }
26640b57cec5SDimitry Andric   // For reserved resources, record the highest cycle using the resource.
26650b57cec5SDimitry Andric   unsigned NextAvailable, InstanceIdx;
266606c3fb27SDimitry Andric   std::tie(NextAvailable, InstanceIdx) =
26675f757f3fSDimitry Andric       getNextResourceCycle(SC, PIdx, ReleaseAtCycle, AcquireAtCycle);
26680b57cec5SDimitry Andric   if (NextAvailable > CurrCycle) {
26690b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  Resource conflict: "
26700b57cec5SDimitry Andric                       << SchedModel->getResourceName(PIdx)
26710b57cec5SDimitry Andric                       << '[' << InstanceIdx - ReservedCyclesIndex[PIdx]  << ']'
26720b57cec5SDimitry Andric                       << " reserved until @" << NextAvailable << "\n");
26730b57cec5SDimitry Andric   }
26740b57cec5SDimitry Andric   return NextAvailable;
26750b57cec5SDimitry Andric }
26760b57cec5SDimitry Andric 
26770b57cec5SDimitry Andric /// Move the boundary of scheduled code by one SUnit.
26780b57cec5SDimitry Andric void SchedBoundary::bumpNode(SUnit *SU) {
26790b57cec5SDimitry Andric   // Update the reservation table.
26800b57cec5SDimitry Andric   if (HazardRec->isEnabled()) {
26810b57cec5SDimitry Andric     if (!isTop() && SU->isCall) {
26820b57cec5SDimitry Andric       // Calls are scheduled with their preceding instructions. For bottom-up
26830b57cec5SDimitry Andric       // scheduling, clear the pipeline state before emitting.
26840b57cec5SDimitry Andric       HazardRec->Reset();
26850b57cec5SDimitry Andric     }
26860b57cec5SDimitry Andric     HazardRec->EmitInstruction(SU);
26870b57cec5SDimitry Andric     // Scheduling an instruction may have made pending instructions available.
26880b57cec5SDimitry Andric     CheckPending = true;
26890b57cec5SDimitry Andric   }
26900b57cec5SDimitry Andric   // checkHazard should prevent scheduling multiple instructions per cycle that
26910b57cec5SDimitry Andric   // exceed the issue width.
26920b57cec5SDimitry Andric   const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
26930b57cec5SDimitry Andric   unsigned IncMOps = SchedModel->getNumMicroOps(SU->getInstr());
26940b57cec5SDimitry Andric   assert(
26950b57cec5SDimitry Andric       (CurrMOps == 0 || (CurrMOps + IncMOps) <= SchedModel->getIssueWidth()) &&
26960b57cec5SDimitry Andric       "Cannot schedule this instruction's MicroOps in the current cycle.");
26970b57cec5SDimitry Andric 
26980b57cec5SDimitry Andric   unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle);
26990b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "  Ready @" << ReadyCycle << "c\n");
27000b57cec5SDimitry Andric 
27010b57cec5SDimitry Andric   unsigned NextCycle = CurrCycle;
27020b57cec5SDimitry Andric   switch (SchedModel->getMicroOpBufferSize()) {
27030b57cec5SDimitry Andric   case 0:
27040b57cec5SDimitry Andric     assert(ReadyCycle <= CurrCycle && "Broken PendingQueue");
27050b57cec5SDimitry Andric     break;
27060b57cec5SDimitry Andric   case 1:
27070b57cec5SDimitry Andric     if (ReadyCycle > NextCycle) {
27080b57cec5SDimitry Andric       NextCycle = ReadyCycle;
27090b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "  *** Stall until: " << ReadyCycle << "\n");
27100b57cec5SDimitry Andric     }
27110b57cec5SDimitry Andric     break;
27120b57cec5SDimitry Andric   default:
27130b57cec5SDimitry Andric     // We don't currently model the OOO reorder buffer, so consider all
27140b57cec5SDimitry Andric     // scheduled MOps to be "retired". We do loosely model in-order resource
27150b57cec5SDimitry Andric     // latency. If this instruction uses an in-order resource, account for any
27160b57cec5SDimitry Andric     // likely stall cycles.
27170b57cec5SDimitry Andric     if (SU->isUnbuffered && ReadyCycle > NextCycle)
27180b57cec5SDimitry Andric       NextCycle = ReadyCycle;
27190b57cec5SDimitry Andric     break;
27200b57cec5SDimitry Andric   }
27210b57cec5SDimitry Andric   RetiredMOps += IncMOps;
27220b57cec5SDimitry Andric 
27230b57cec5SDimitry Andric   // Update resource counts and critical resource.
27240b57cec5SDimitry Andric   if (SchedModel->hasInstrSchedModel()) {
27250b57cec5SDimitry Andric     unsigned DecRemIssue = IncMOps * SchedModel->getMicroOpFactor();
27260b57cec5SDimitry Andric     assert(Rem->RemIssueCount >= DecRemIssue && "MOps double counted");
27270b57cec5SDimitry Andric     Rem->RemIssueCount -= DecRemIssue;
27280b57cec5SDimitry Andric     if (ZoneCritResIdx) {
27290b57cec5SDimitry Andric       // Scale scheduled micro-ops for comparing with the critical resource.
27300b57cec5SDimitry Andric       unsigned ScaledMOps =
27310b57cec5SDimitry Andric         RetiredMOps * SchedModel->getMicroOpFactor();
27320b57cec5SDimitry Andric 
27330b57cec5SDimitry Andric       // If scaled micro-ops are now more than the previous critical resource by
27340b57cec5SDimitry Andric       // a full cycle, then micro-ops issue becomes critical.
27350b57cec5SDimitry Andric       if ((int)(ScaledMOps - getResourceCount(ZoneCritResIdx))
27360b57cec5SDimitry Andric           >= (int)SchedModel->getLatencyFactor()) {
27370b57cec5SDimitry Andric         ZoneCritResIdx = 0;
27380b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "  *** Critical resource NumMicroOps: "
27390b57cec5SDimitry Andric                           << ScaledMOps / SchedModel->getLatencyFactor()
27400b57cec5SDimitry Andric                           << "c\n");
27410b57cec5SDimitry Andric       }
27420b57cec5SDimitry Andric     }
27430b57cec5SDimitry Andric     for (TargetSchedModel::ProcResIter
27440b57cec5SDimitry Andric            PI = SchedModel->getWriteProcResBegin(SC),
27450b57cec5SDimitry Andric            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
27465f757f3fSDimitry Andric       unsigned RCycle =
27475f757f3fSDimitry Andric           countResource(SC, PI->ProcResourceIdx, PI->ReleaseAtCycle, NextCycle,
27485f757f3fSDimitry Andric                         PI->AcquireAtCycle);
27490b57cec5SDimitry Andric       if (RCycle > NextCycle)
27500b57cec5SDimitry Andric         NextCycle = RCycle;
27510b57cec5SDimitry Andric     }
27520b57cec5SDimitry Andric     if (SU->hasReservedResource) {
27530b57cec5SDimitry Andric       // For reserved resources, record the highest cycle using the resource.
27540b57cec5SDimitry Andric       // For top-down scheduling, this is the cycle in which we schedule this
27550b57cec5SDimitry Andric       // instruction plus the number of cycles the operations reserves the
27560b57cec5SDimitry Andric       // resource. For bottom-up is it simply the instruction's cycle.
27570b57cec5SDimitry Andric       for (TargetSchedModel::ProcResIter
27580b57cec5SDimitry Andric              PI = SchedModel->getWriteProcResBegin(SC),
27590b57cec5SDimitry Andric              PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
27600b57cec5SDimitry Andric         unsigned PIdx = PI->ProcResourceIdx;
27610b57cec5SDimitry Andric         if (SchedModel->getProcResource(PIdx)->BufferSize == 0) {
276206c3fb27SDimitry Andric 
276306c3fb27SDimitry Andric           if (SchedModel && SchedModel->enableIntervals()) {
27640b57cec5SDimitry Andric             unsigned ReservedUntil, InstanceIdx;
27655f757f3fSDimitry Andric             std::tie(ReservedUntil, InstanceIdx) = getNextResourceCycle(
27665f757f3fSDimitry Andric                 SC, PIdx, PI->ReleaseAtCycle, PI->AcquireAtCycle);
276706c3fb27SDimitry Andric             if (isTop()) {
276806c3fb27SDimitry Andric               ReservedResourceSegments[InstanceIdx].add(
276906c3fb27SDimitry Andric                   ResourceSegments::getResourceIntervalTop(
27705f757f3fSDimitry Andric                       NextCycle, PI->AcquireAtCycle, PI->ReleaseAtCycle),
277106c3fb27SDimitry Andric                   MIResourceCutOff);
277206c3fb27SDimitry Andric             } else {
277306c3fb27SDimitry Andric               ReservedResourceSegments[InstanceIdx].add(
277406c3fb27SDimitry Andric                   ResourceSegments::getResourceIntervalBottom(
27755f757f3fSDimitry Andric                       NextCycle, PI->AcquireAtCycle, PI->ReleaseAtCycle),
277606c3fb27SDimitry Andric                   MIResourceCutOff);
277706c3fb27SDimitry Andric             }
277806c3fb27SDimitry Andric           } else {
277906c3fb27SDimitry Andric 
278006c3fb27SDimitry Andric             unsigned ReservedUntil, InstanceIdx;
27815f757f3fSDimitry Andric             std::tie(ReservedUntil, InstanceIdx) = getNextResourceCycle(
27825f757f3fSDimitry Andric                 SC, PIdx, PI->ReleaseAtCycle, PI->AcquireAtCycle);
27830b57cec5SDimitry Andric             if (isTop()) {
27840b57cec5SDimitry Andric               ReservedCycles[InstanceIdx] =
27855f757f3fSDimitry Andric                   std::max(ReservedUntil, NextCycle + PI->ReleaseAtCycle);
27860b57cec5SDimitry Andric             } else
27870b57cec5SDimitry Andric               ReservedCycles[InstanceIdx] = NextCycle;
27880b57cec5SDimitry Andric           }
27890b57cec5SDimitry Andric         }
27900b57cec5SDimitry Andric       }
27910b57cec5SDimitry Andric     }
279206c3fb27SDimitry Andric   }
27930b57cec5SDimitry Andric   // Update ExpectedLatency and DependentLatency.
27940b57cec5SDimitry Andric   unsigned &TopLatency = isTop() ? ExpectedLatency : DependentLatency;
27950b57cec5SDimitry Andric   unsigned &BotLatency = isTop() ? DependentLatency : ExpectedLatency;
27960b57cec5SDimitry Andric   if (SU->getDepth() > TopLatency) {
27970b57cec5SDimitry Andric     TopLatency = SU->getDepth();
27980b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << Available.getName() << " TopLatency SU("
27990b57cec5SDimitry Andric                       << SU->NodeNum << ") " << TopLatency << "c\n");
28000b57cec5SDimitry Andric   }
28010b57cec5SDimitry Andric   if (SU->getHeight() > BotLatency) {
28020b57cec5SDimitry Andric     BotLatency = SU->getHeight();
28030b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << Available.getName() << " BotLatency SU("
28040b57cec5SDimitry Andric                       << SU->NodeNum << ") " << BotLatency << "c\n");
28050b57cec5SDimitry Andric   }
28060b57cec5SDimitry Andric   // If we stall for any reason, bump the cycle.
28070b57cec5SDimitry Andric   if (NextCycle > CurrCycle)
28080b57cec5SDimitry Andric     bumpCycle(NextCycle);
28090b57cec5SDimitry Andric   else
28100b57cec5SDimitry Andric     // After updating ZoneCritResIdx and ExpectedLatency, check if we're
28110b57cec5SDimitry Andric     // resource limited. If a stall occurred, bumpCycle does this.
28120b57cec5SDimitry Andric     IsResourceLimited =
28130b57cec5SDimitry Andric         checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(),
28140b57cec5SDimitry Andric                            getScheduledLatency(), true);
28150b57cec5SDimitry Andric 
28160b57cec5SDimitry Andric   // Update CurrMOps after calling bumpCycle to handle stalls, since bumpCycle
28170b57cec5SDimitry Andric   // resets CurrMOps. Loop to handle instructions with more MOps than issue in
28180b57cec5SDimitry Andric   // one cycle.  Since we commonly reach the max MOps here, opportunistically
28190b57cec5SDimitry Andric   // bump the cycle to avoid uselessly checking everything in the readyQ.
28200b57cec5SDimitry Andric   CurrMOps += IncMOps;
28210b57cec5SDimitry Andric 
28220b57cec5SDimitry Andric   // Bump the cycle count for issue group constraints.
28230b57cec5SDimitry Andric   // This must be done after NextCycle has been adjust for all other stalls.
28240b57cec5SDimitry Andric   // Calling bumpCycle(X) will reduce CurrMOps by one issue group and set
28250b57cec5SDimitry Andric   // currCycle to X.
28260b57cec5SDimitry Andric   if ((isTop() &&  SchedModel->mustEndGroup(SU->getInstr())) ||
28270b57cec5SDimitry Andric       (!isTop() && SchedModel->mustBeginGroup(SU->getInstr()))) {
28280b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  Bump cycle to " << (isTop() ? "end" : "begin")
28290b57cec5SDimitry Andric                       << " group\n");
28300b57cec5SDimitry Andric     bumpCycle(++NextCycle);
28310b57cec5SDimitry Andric   }
28320b57cec5SDimitry Andric 
28330b57cec5SDimitry Andric   while (CurrMOps >= SchedModel->getIssueWidth()) {
28340b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  *** Max MOps " << CurrMOps << " at cycle "
28350b57cec5SDimitry Andric                       << CurrCycle << '\n');
28360b57cec5SDimitry Andric     bumpCycle(++NextCycle);
28370b57cec5SDimitry Andric   }
28380b57cec5SDimitry Andric   LLVM_DEBUG(dumpScheduledState());
28390b57cec5SDimitry Andric }
28400b57cec5SDimitry Andric 
28410b57cec5SDimitry Andric /// Release pending ready nodes in to the available queue. This makes them
28420b57cec5SDimitry Andric /// visible to heuristics.
28430b57cec5SDimitry Andric void SchedBoundary::releasePending() {
28440b57cec5SDimitry Andric   // If the available queue is empty, it is safe to reset MinReadyCycle.
28450b57cec5SDimitry Andric   if (Available.empty())
28460b57cec5SDimitry Andric     MinReadyCycle = std::numeric_limits<unsigned>::max();
28470b57cec5SDimitry Andric 
28480b57cec5SDimitry Andric   // Check to see if any of the pending instructions are ready to issue.  If
28490b57cec5SDimitry Andric   // so, add them to the available queue.
2850480093f4SDimitry Andric   for (unsigned I = 0, E = Pending.size(); I < E; ++I) {
2851480093f4SDimitry Andric     SUnit *SU = *(Pending.begin() + I);
28520b57cec5SDimitry Andric     unsigned ReadyCycle = isTop() ? SU->TopReadyCycle : SU->BotReadyCycle;
28530b57cec5SDimitry Andric 
28540b57cec5SDimitry Andric     if (ReadyCycle < MinReadyCycle)
28550b57cec5SDimitry Andric       MinReadyCycle = ReadyCycle;
28560b57cec5SDimitry Andric 
28570b57cec5SDimitry Andric     if (Available.size() >= ReadyListLimit)
28580b57cec5SDimitry Andric       break;
28590b57cec5SDimitry Andric 
2860480093f4SDimitry Andric     releaseNode(SU, ReadyCycle, true, I);
2861480093f4SDimitry Andric     if (E != Pending.size()) {
2862480093f4SDimitry Andric       --I;
2863480093f4SDimitry Andric       --E;
2864480093f4SDimitry Andric     }
28650b57cec5SDimitry Andric   }
28660b57cec5SDimitry Andric   CheckPending = false;
28670b57cec5SDimitry Andric }
28680b57cec5SDimitry Andric 
28690b57cec5SDimitry Andric /// Remove SU from the ready set for this boundary.
28700b57cec5SDimitry Andric void SchedBoundary::removeReady(SUnit *SU) {
28710b57cec5SDimitry Andric   if (Available.isInQueue(SU))
28720b57cec5SDimitry Andric     Available.remove(Available.find(SU));
28730b57cec5SDimitry Andric   else {
28740b57cec5SDimitry Andric     assert(Pending.isInQueue(SU) && "bad ready count");
28750b57cec5SDimitry Andric     Pending.remove(Pending.find(SU));
28760b57cec5SDimitry Andric   }
28770b57cec5SDimitry Andric }
28780b57cec5SDimitry Andric 
28790b57cec5SDimitry Andric /// If this queue only has one ready candidate, return it. As a side effect,
28800b57cec5SDimitry Andric /// defer any nodes that now hit a hazard, and advance the cycle until at least
28810b57cec5SDimitry Andric /// one node is ready. If multiple instructions are ready, return NULL.
28820b57cec5SDimitry Andric SUnit *SchedBoundary::pickOnlyChoice() {
28830b57cec5SDimitry Andric   if (CheckPending)
28840b57cec5SDimitry Andric     releasePending();
28850b57cec5SDimitry Andric 
28860b57cec5SDimitry Andric   // Defer any ready instrs that now have a hazard.
28870b57cec5SDimitry Andric   for (ReadyQueue::iterator I = Available.begin(); I != Available.end();) {
28880b57cec5SDimitry Andric     if (checkHazard(*I)) {
28890b57cec5SDimitry Andric       Pending.push(*I);
28900b57cec5SDimitry Andric       I = Available.remove(I);
28910b57cec5SDimitry Andric       continue;
28920b57cec5SDimitry Andric     }
28930b57cec5SDimitry Andric     ++I;
28940b57cec5SDimitry Andric   }
28950b57cec5SDimitry Andric   for (unsigned i = 0; Available.empty(); ++i) {
28960b57cec5SDimitry Andric //  FIXME: Re-enable assert once PR20057 is resolved.
28970b57cec5SDimitry Andric //    assert(i <= (HazardRec->getMaxLookAhead() + MaxObservedStall) &&
28980b57cec5SDimitry Andric //           "permanent hazard");
28990b57cec5SDimitry Andric     (void)i;
29000b57cec5SDimitry Andric     bumpCycle(CurrCycle + 1);
29010b57cec5SDimitry Andric     releasePending();
29020b57cec5SDimitry Andric   }
29030b57cec5SDimitry Andric 
29040b57cec5SDimitry Andric   LLVM_DEBUG(Pending.dump());
29050b57cec5SDimitry Andric   LLVM_DEBUG(Available.dump());
29060b57cec5SDimitry Andric 
29070b57cec5SDimitry Andric   if (Available.size() == 1)
29080b57cec5SDimitry Andric     return *Available.begin();
29090b57cec5SDimitry Andric   return nullptr;
29100b57cec5SDimitry Andric }
29110b57cec5SDimitry Andric 
29120b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2913bdd1243dSDimitry Andric 
2914bdd1243dSDimitry Andric /// Dump the content of the \ref ReservedCycles vector for the
2915bdd1243dSDimitry Andric /// resources that are used in the basic block.
2916bdd1243dSDimitry Andric ///
2917bdd1243dSDimitry Andric LLVM_DUMP_METHOD void SchedBoundary::dumpReservedCycles() const {
2918bdd1243dSDimitry Andric   if (!SchedModel->hasInstrSchedModel())
2919bdd1243dSDimitry Andric     return;
2920bdd1243dSDimitry Andric 
2921bdd1243dSDimitry Andric   unsigned ResourceCount = SchedModel->getNumProcResourceKinds();
2922bdd1243dSDimitry Andric   unsigned StartIdx = 0;
2923bdd1243dSDimitry Andric 
2924bdd1243dSDimitry Andric   for (unsigned ResIdx = 0; ResIdx < ResourceCount; ++ResIdx) {
2925bdd1243dSDimitry Andric     const unsigned NumUnits = SchedModel->getProcResource(ResIdx)->NumUnits;
2926bdd1243dSDimitry Andric     std::string ResName = SchedModel->getResourceName(ResIdx);
2927bdd1243dSDimitry Andric     for (unsigned UnitIdx = 0; UnitIdx < NumUnits; ++UnitIdx) {
292806c3fb27SDimitry Andric       dbgs() << ResName << "(" << UnitIdx << ") = ";
292906c3fb27SDimitry Andric       if (SchedModel && SchedModel->enableIntervals()) {
293006c3fb27SDimitry Andric         if (ReservedResourceSegments.count(StartIdx + UnitIdx))
293106c3fb27SDimitry Andric           dbgs() << ReservedResourceSegments.at(StartIdx + UnitIdx);
293206c3fb27SDimitry Andric         else
293306c3fb27SDimitry Andric           dbgs() << "{ }\n";
293406c3fb27SDimitry Andric       } else
293506c3fb27SDimitry Andric         dbgs() << ReservedCycles[StartIdx + UnitIdx] << "\n";
2936bdd1243dSDimitry Andric     }
2937bdd1243dSDimitry Andric     StartIdx += NumUnits;
2938bdd1243dSDimitry Andric   }
2939bdd1243dSDimitry Andric }
2940bdd1243dSDimitry Andric 
29410b57cec5SDimitry Andric // This is useful information to dump after bumpNode.
29420b57cec5SDimitry Andric // Note that the Queue contents are more useful before pickNodeFromQueue.
29430b57cec5SDimitry Andric LLVM_DUMP_METHOD void SchedBoundary::dumpScheduledState() const {
29440b57cec5SDimitry Andric   unsigned ResFactor;
29450b57cec5SDimitry Andric   unsigned ResCount;
29460b57cec5SDimitry Andric   if (ZoneCritResIdx) {
29470b57cec5SDimitry Andric     ResFactor = SchedModel->getResourceFactor(ZoneCritResIdx);
29480b57cec5SDimitry Andric     ResCount = getResourceCount(ZoneCritResIdx);
29490b57cec5SDimitry Andric   } else {
29500b57cec5SDimitry Andric     ResFactor = SchedModel->getMicroOpFactor();
29510b57cec5SDimitry Andric     ResCount = RetiredMOps * ResFactor;
29520b57cec5SDimitry Andric   }
29530b57cec5SDimitry Andric   unsigned LFactor = SchedModel->getLatencyFactor();
29540b57cec5SDimitry Andric   dbgs() << Available.getName() << " @" << CurrCycle << "c\n"
29550b57cec5SDimitry Andric          << "  Retired: " << RetiredMOps;
29560b57cec5SDimitry Andric   dbgs() << "\n  Executed: " << getExecutedCount() / LFactor << "c";
29570b57cec5SDimitry Andric   dbgs() << "\n  Critical: " << ResCount / LFactor << "c, "
29580b57cec5SDimitry Andric          << ResCount / ResFactor << " "
29590b57cec5SDimitry Andric          << SchedModel->getResourceName(ZoneCritResIdx)
29600b57cec5SDimitry Andric          << "\n  ExpectedLatency: " << ExpectedLatency << "c\n"
29610b57cec5SDimitry Andric          << (IsResourceLimited ? "  - Resource" : "  - Latency")
29620b57cec5SDimitry Andric          << " limited.\n";
2963bdd1243dSDimitry Andric   if (MISchedDumpReservedCycles)
2964bdd1243dSDimitry Andric     dumpReservedCycles();
29650b57cec5SDimitry Andric }
29660b57cec5SDimitry Andric #endif
29670b57cec5SDimitry Andric 
29680b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
29690b57cec5SDimitry Andric // GenericScheduler - Generic implementation of MachineSchedStrategy.
29700b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
29710b57cec5SDimitry Andric 
29720b57cec5SDimitry Andric void GenericSchedulerBase::SchedCandidate::
29730b57cec5SDimitry Andric initResourceDelta(const ScheduleDAGMI *DAG,
29740b57cec5SDimitry Andric                   const TargetSchedModel *SchedModel) {
29750b57cec5SDimitry Andric   if (!Policy.ReduceResIdx && !Policy.DemandResIdx)
29760b57cec5SDimitry Andric     return;
29770b57cec5SDimitry Andric 
29780b57cec5SDimitry Andric   const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
29790b57cec5SDimitry Andric   for (TargetSchedModel::ProcResIter
29800b57cec5SDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
29810b57cec5SDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
29820b57cec5SDimitry Andric     if (PI->ProcResourceIdx == Policy.ReduceResIdx)
29835f757f3fSDimitry Andric       ResDelta.CritResources += PI->ReleaseAtCycle;
29840b57cec5SDimitry Andric     if (PI->ProcResourceIdx == Policy.DemandResIdx)
29855f757f3fSDimitry Andric       ResDelta.DemandedResources += PI->ReleaseAtCycle;
29860b57cec5SDimitry Andric   }
29870b57cec5SDimitry Andric }
29880b57cec5SDimitry Andric 
29890b57cec5SDimitry Andric /// Compute remaining latency. We need this both to determine whether the
29900b57cec5SDimitry Andric /// overall schedule has become latency-limited and whether the instructions
29910b57cec5SDimitry Andric /// outside this zone are resource or latency limited.
29920b57cec5SDimitry Andric ///
29930b57cec5SDimitry Andric /// The "dependent" latency is updated incrementally during scheduling as the
29940b57cec5SDimitry Andric /// max height/depth of scheduled nodes minus the cycles since it was
29950b57cec5SDimitry Andric /// scheduled:
29960b57cec5SDimitry Andric ///   DLat = max (N.depth - (CurrCycle - N.ReadyCycle) for N in Zone
29970b57cec5SDimitry Andric ///
29980b57cec5SDimitry Andric /// The "independent" latency is the max ready queue depth:
29990b57cec5SDimitry Andric ///   ILat = max N.depth for N in Available|Pending
30000b57cec5SDimitry Andric ///
30010b57cec5SDimitry Andric /// RemainingLatency is the greater of independent and dependent latency.
30020b57cec5SDimitry Andric ///
30030b57cec5SDimitry Andric /// These computations are expensive, especially in DAGs with many edges, so
30040b57cec5SDimitry Andric /// only do them if necessary.
30050b57cec5SDimitry Andric static unsigned computeRemLatency(SchedBoundary &CurrZone) {
30060b57cec5SDimitry Andric   unsigned RemLatency = CurrZone.getDependentLatency();
30070b57cec5SDimitry Andric   RemLatency = std::max(RemLatency,
30080b57cec5SDimitry Andric                         CurrZone.findMaxLatency(CurrZone.Available.elements()));
30090b57cec5SDimitry Andric   RemLatency = std::max(RemLatency,
30100b57cec5SDimitry Andric                         CurrZone.findMaxLatency(CurrZone.Pending.elements()));
30110b57cec5SDimitry Andric   return RemLatency;
30120b57cec5SDimitry Andric }
30130b57cec5SDimitry Andric 
30140b57cec5SDimitry Andric /// Returns true if the current cycle plus remaning latency is greater than
30150b57cec5SDimitry Andric /// the critical path in the scheduling region.
30160b57cec5SDimitry Andric bool GenericSchedulerBase::shouldReduceLatency(const CandPolicy &Policy,
30170b57cec5SDimitry Andric                                                SchedBoundary &CurrZone,
30180b57cec5SDimitry Andric                                                bool ComputeRemLatency,
30190b57cec5SDimitry Andric                                                unsigned &RemLatency) const {
30200b57cec5SDimitry Andric   // The current cycle is already greater than the critical path, so we are
30210b57cec5SDimitry Andric   // already latency limited and don't need to compute the remaining latency.
30220b57cec5SDimitry Andric   if (CurrZone.getCurrCycle() > Rem.CriticalPath)
30230b57cec5SDimitry Andric     return true;
30240b57cec5SDimitry Andric 
30250b57cec5SDimitry Andric   // If we haven't scheduled anything yet, then we aren't latency limited.
30260b57cec5SDimitry Andric   if (CurrZone.getCurrCycle() == 0)
30270b57cec5SDimitry Andric     return false;
30280b57cec5SDimitry Andric 
30290b57cec5SDimitry Andric   if (ComputeRemLatency)
30300b57cec5SDimitry Andric     RemLatency = computeRemLatency(CurrZone);
30310b57cec5SDimitry Andric 
30320b57cec5SDimitry Andric   return RemLatency + CurrZone.getCurrCycle() > Rem.CriticalPath;
30330b57cec5SDimitry Andric }
30340b57cec5SDimitry Andric 
30350b57cec5SDimitry Andric /// Set the CandPolicy given a scheduling zone given the current resources and
30360b57cec5SDimitry Andric /// latencies inside and outside the zone.
30370b57cec5SDimitry Andric void GenericSchedulerBase::setPolicy(CandPolicy &Policy, bool IsPostRA,
30380b57cec5SDimitry Andric                                      SchedBoundary &CurrZone,
30390b57cec5SDimitry Andric                                      SchedBoundary *OtherZone) {
30400b57cec5SDimitry Andric   // Apply preemptive heuristics based on the total latency and resources
30410b57cec5SDimitry Andric   // inside and outside this zone. Potential stalls should be considered before
30420b57cec5SDimitry Andric   // following this policy.
30430b57cec5SDimitry Andric 
30440b57cec5SDimitry Andric   // Compute the critical resource outside the zone.
30450b57cec5SDimitry Andric   unsigned OtherCritIdx = 0;
30460b57cec5SDimitry Andric   unsigned OtherCount =
30470b57cec5SDimitry Andric     OtherZone ? OtherZone->getOtherResourceCount(OtherCritIdx) : 0;
30480b57cec5SDimitry Andric 
30490b57cec5SDimitry Andric   bool OtherResLimited = false;
30500b57cec5SDimitry Andric   unsigned RemLatency = 0;
30510b57cec5SDimitry Andric   bool RemLatencyComputed = false;
30520b57cec5SDimitry Andric   if (SchedModel->hasInstrSchedModel() && OtherCount != 0) {
30530b57cec5SDimitry Andric     RemLatency = computeRemLatency(CurrZone);
30540b57cec5SDimitry Andric     RemLatencyComputed = true;
30550b57cec5SDimitry Andric     OtherResLimited = checkResourceLimit(SchedModel->getLatencyFactor(),
30560b57cec5SDimitry Andric                                          OtherCount, RemLatency, false);
30570b57cec5SDimitry Andric   }
30580b57cec5SDimitry Andric 
30590b57cec5SDimitry Andric   // Schedule aggressively for latency in PostRA mode. We don't check for
30600b57cec5SDimitry Andric   // acyclic latency during PostRA, and highly out-of-order processors will
30610b57cec5SDimitry Andric   // skip PostRA scheduling.
30620b57cec5SDimitry Andric   if (!OtherResLimited &&
30630b57cec5SDimitry Andric       (IsPostRA || shouldReduceLatency(Policy, CurrZone, !RemLatencyComputed,
30640b57cec5SDimitry Andric                                        RemLatency))) {
30650b57cec5SDimitry Andric     Policy.ReduceLatency |= true;
30660b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << CurrZone.Available.getName()
30670b57cec5SDimitry Andric                       << " RemainingLatency " << RemLatency << " + "
30680b57cec5SDimitry Andric                       << CurrZone.getCurrCycle() << "c > CritPath "
30690b57cec5SDimitry Andric                       << Rem.CriticalPath << "\n");
30700b57cec5SDimitry Andric   }
30710b57cec5SDimitry Andric   // If the same resource is limiting inside and outside the zone, do nothing.
30720b57cec5SDimitry Andric   if (CurrZone.getZoneCritResIdx() == OtherCritIdx)
30730b57cec5SDimitry Andric     return;
30740b57cec5SDimitry Andric 
30750b57cec5SDimitry Andric   LLVM_DEBUG(if (CurrZone.isResourceLimited()) {
30760b57cec5SDimitry Andric     dbgs() << "  " << CurrZone.Available.getName() << " ResourceLimited: "
30770b57cec5SDimitry Andric            << SchedModel->getResourceName(CurrZone.getZoneCritResIdx()) << "\n";
30780b57cec5SDimitry Andric   } if (OtherResLimited) dbgs()
30790b57cec5SDimitry Andric                  << "  RemainingLimit: "
30800b57cec5SDimitry Andric                  << SchedModel->getResourceName(OtherCritIdx) << "\n";
30810b57cec5SDimitry Andric              if (!CurrZone.isResourceLimited() && !OtherResLimited) dbgs()
30820b57cec5SDimitry Andric              << "  Latency limited both directions.\n");
30830b57cec5SDimitry Andric 
30840b57cec5SDimitry Andric   if (CurrZone.isResourceLimited() && !Policy.ReduceResIdx)
30850b57cec5SDimitry Andric     Policy.ReduceResIdx = CurrZone.getZoneCritResIdx();
30860b57cec5SDimitry Andric 
30870b57cec5SDimitry Andric   if (OtherResLimited)
30880b57cec5SDimitry Andric     Policy.DemandResIdx = OtherCritIdx;
30890b57cec5SDimitry Andric }
30900b57cec5SDimitry Andric 
30910b57cec5SDimitry Andric #ifndef NDEBUG
30920b57cec5SDimitry Andric const char *GenericSchedulerBase::getReasonStr(
30930b57cec5SDimitry Andric   GenericSchedulerBase::CandReason Reason) {
30940b57cec5SDimitry Andric   switch (Reason) {
30950b57cec5SDimitry Andric   case NoCand:         return "NOCAND    ";
30960b57cec5SDimitry Andric   case Only1:          return "ONLY1     ";
30970b57cec5SDimitry Andric   case PhysReg:        return "PHYS-REG  ";
30980b57cec5SDimitry Andric   case RegExcess:      return "REG-EXCESS";
30990b57cec5SDimitry Andric   case RegCritical:    return "REG-CRIT  ";
31000b57cec5SDimitry Andric   case Stall:          return "STALL     ";
31010b57cec5SDimitry Andric   case Cluster:        return "CLUSTER   ";
31020b57cec5SDimitry Andric   case Weak:           return "WEAK      ";
31030b57cec5SDimitry Andric   case RegMax:         return "REG-MAX   ";
31040b57cec5SDimitry Andric   case ResourceReduce: return "RES-REDUCE";
31050b57cec5SDimitry Andric   case ResourceDemand: return "RES-DEMAND";
31060b57cec5SDimitry Andric   case TopDepthReduce: return "TOP-DEPTH ";
31070b57cec5SDimitry Andric   case TopPathReduce:  return "TOP-PATH  ";
31080b57cec5SDimitry Andric   case BotHeightReduce:return "BOT-HEIGHT";
31090b57cec5SDimitry Andric   case BotPathReduce:  return "BOT-PATH  ";
31100b57cec5SDimitry Andric   case NextDefUse:     return "DEF-USE   ";
31110b57cec5SDimitry Andric   case NodeOrder:      return "ORDER     ";
31120b57cec5SDimitry Andric   };
31130b57cec5SDimitry Andric   llvm_unreachable("Unknown reason!");
31140b57cec5SDimitry Andric }
31150b57cec5SDimitry Andric 
31160b57cec5SDimitry Andric void GenericSchedulerBase::traceCandidate(const SchedCandidate &Cand) {
31170b57cec5SDimitry Andric   PressureChange P;
31180b57cec5SDimitry Andric   unsigned ResIdx = 0;
31190b57cec5SDimitry Andric   unsigned Latency = 0;
31200b57cec5SDimitry Andric   switch (Cand.Reason) {
31210b57cec5SDimitry Andric   default:
31220b57cec5SDimitry Andric     break;
31230b57cec5SDimitry Andric   case RegExcess:
31240b57cec5SDimitry Andric     P = Cand.RPDelta.Excess;
31250b57cec5SDimitry Andric     break;
31260b57cec5SDimitry Andric   case RegCritical:
31270b57cec5SDimitry Andric     P = Cand.RPDelta.CriticalMax;
31280b57cec5SDimitry Andric     break;
31290b57cec5SDimitry Andric   case RegMax:
31300b57cec5SDimitry Andric     P = Cand.RPDelta.CurrentMax;
31310b57cec5SDimitry Andric     break;
31320b57cec5SDimitry Andric   case ResourceReduce:
31330b57cec5SDimitry Andric     ResIdx = Cand.Policy.ReduceResIdx;
31340b57cec5SDimitry Andric     break;
31350b57cec5SDimitry Andric   case ResourceDemand:
31360b57cec5SDimitry Andric     ResIdx = Cand.Policy.DemandResIdx;
31370b57cec5SDimitry Andric     break;
31380b57cec5SDimitry Andric   case TopDepthReduce:
31390b57cec5SDimitry Andric     Latency = Cand.SU->getDepth();
31400b57cec5SDimitry Andric     break;
31410b57cec5SDimitry Andric   case TopPathReduce:
31420b57cec5SDimitry Andric     Latency = Cand.SU->getHeight();
31430b57cec5SDimitry Andric     break;
31440b57cec5SDimitry Andric   case BotHeightReduce:
31450b57cec5SDimitry Andric     Latency = Cand.SU->getHeight();
31460b57cec5SDimitry Andric     break;
31470b57cec5SDimitry Andric   case BotPathReduce:
31480b57cec5SDimitry Andric     Latency = Cand.SU->getDepth();
31490b57cec5SDimitry Andric     break;
31500b57cec5SDimitry Andric   }
31510b57cec5SDimitry Andric   dbgs() << "  Cand SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason);
31520b57cec5SDimitry Andric   if (P.isValid())
31530b57cec5SDimitry Andric     dbgs() << " " << TRI->getRegPressureSetName(P.getPSet())
31540b57cec5SDimitry Andric            << ":" << P.getUnitInc() << " ";
31550b57cec5SDimitry Andric   else
31560b57cec5SDimitry Andric     dbgs() << "      ";
31570b57cec5SDimitry Andric   if (ResIdx)
31580b57cec5SDimitry Andric     dbgs() << " " << SchedModel->getProcResource(ResIdx)->Name << " ";
31590b57cec5SDimitry Andric   else
31600b57cec5SDimitry Andric     dbgs() << "         ";
31610b57cec5SDimitry Andric   if (Latency)
31620b57cec5SDimitry Andric     dbgs() << " " << Latency << " cycles ";
31630b57cec5SDimitry Andric   else
31640b57cec5SDimitry Andric     dbgs() << "          ";
31650b57cec5SDimitry Andric   dbgs() << '\n';
31660b57cec5SDimitry Andric }
31670b57cec5SDimitry Andric #endif
31680b57cec5SDimitry Andric 
31690b57cec5SDimitry Andric namespace llvm {
31700b57cec5SDimitry Andric /// Return true if this heuristic determines order.
3171fe6060f1SDimitry Andric /// TODO: Consider refactor return type of these functions as integer or enum,
3172fe6060f1SDimitry Andric /// as we may need to differentiate whether TryCand is better than Cand.
31730b57cec5SDimitry Andric bool tryLess(int TryVal, int CandVal,
31740b57cec5SDimitry Andric              GenericSchedulerBase::SchedCandidate &TryCand,
31750b57cec5SDimitry Andric              GenericSchedulerBase::SchedCandidate &Cand,
31760b57cec5SDimitry Andric              GenericSchedulerBase::CandReason Reason) {
31770b57cec5SDimitry Andric   if (TryVal < CandVal) {
31780b57cec5SDimitry Andric     TryCand.Reason = Reason;
31790b57cec5SDimitry Andric     return true;
31800b57cec5SDimitry Andric   }
31810b57cec5SDimitry Andric   if (TryVal > CandVal) {
31820b57cec5SDimitry Andric     if (Cand.Reason > Reason)
31830b57cec5SDimitry Andric       Cand.Reason = Reason;
31840b57cec5SDimitry Andric     return true;
31850b57cec5SDimitry Andric   }
31860b57cec5SDimitry Andric   return false;
31870b57cec5SDimitry Andric }
31880b57cec5SDimitry Andric 
31890b57cec5SDimitry Andric bool tryGreater(int TryVal, int CandVal,
31900b57cec5SDimitry Andric                 GenericSchedulerBase::SchedCandidate &TryCand,
31910b57cec5SDimitry Andric                 GenericSchedulerBase::SchedCandidate &Cand,
31920b57cec5SDimitry Andric                 GenericSchedulerBase::CandReason Reason) {
31930b57cec5SDimitry Andric   if (TryVal > CandVal) {
31940b57cec5SDimitry Andric     TryCand.Reason = Reason;
31950b57cec5SDimitry Andric     return true;
31960b57cec5SDimitry Andric   }
31970b57cec5SDimitry Andric   if (TryVal < CandVal) {
31980b57cec5SDimitry Andric     if (Cand.Reason > Reason)
31990b57cec5SDimitry Andric       Cand.Reason = Reason;
32000b57cec5SDimitry Andric     return true;
32010b57cec5SDimitry Andric   }
32020b57cec5SDimitry Andric   return false;
32030b57cec5SDimitry Andric }
32040b57cec5SDimitry Andric 
32050b57cec5SDimitry Andric bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand,
32060b57cec5SDimitry Andric                 GenericSchedulerBase::SchedCandidate &Cand,
32070b57cec5SDimitry Andric                 SchedBoundary &Zone) {
32080b57cec5SDimitry Andric   if (Zone.isTop()) {
3209e8d8bef9SDimitry Andric     // Prefer the candidate with the lesser depth, but only if one of them has
3210e8d8bef9SDimitry Andric     // depth greater than the total latency scheduled so far, otherwise either
3211e8d8bef9SDimitry Andric     // of them could be scheduled now with no stall.
3212e8d8bef9SDimitry Andric     if (std::max(TryCand.SU->getDepth(), Cand.SU->getDepth()) >
3213e8d8bef9SDimitry Andric         Zone.getScheduledLatency()) {
32140b57cec5SDimitry Andric       if (tryLess(TryCand.SU->getDepth(), Cand.SU->getDepth(),
32150b57cec5SDimitry Andric                   TryCand, Cand, GenericSchedulerBase::TopDepthReduce))
32160b57cec5SDimitry Andric         return true;
32170b57cec5SDimitry Andric     }
32180b57cec5SDimitry Andric     if (tryGreater(TryCand.SU->getHeight(), Cand.SU->getHeight(),
32190b57cec5SDimitry Andric                    TryCand, Cand, GenericSchedulerBase::TopPathReduce))
32200b57cec5SDimitry Andric       return true;
32210b57cec5SDimitry Andric   } else {
3222e8d8bef9SDimitry Andric     // Prefer the candidate with the lesser height, but only if one of them has
3223e8d8bef9SDimitry Andric     // height greater than the total latency scheduled so far, otherwise either
3224e8d8bef9SDimitry Andric     // of them could be scheduled now with no stall.
3225e8d8bef9SDimitry Andric     if (std::max(TryCand.SU->getHeight(), Cand.SU->getHeight()) >
3226e8d8bef9SDimitry Andric         Zone.getScheduledLatency()) {
32270b57cec5SDimitry Andric       if (tryLess(TryCand.SU->getHeight(), Cand.SU->getHeight(),
32280b57cec5SDimitry Andric                   TryCand, Cand, GenericSchedulerBase::BotHeightReduce))
32290b57cec5SDimitry Andric         return true;
32300b57cec5SDimitry Andric     }
32310b57cec5SDimitry Andric     if (tryGreater(TryCand.SU->getDepth(), Cand.SU->getDepth(),
32320b57cec5SDimitry Andric                    TryCand, Cand, GenericSchedulerBase::BotPathReduce))
32330b57cec5SDimitry Andric       return true;
32340b57cec5SDimitry Andric   }
32350b57cec5SDimitry Andric   return false;
32360b57cec5SDimitry Andric }
32370b57cec5SDimitry Andric } // end namespace llvm
32380b57cec5SDimitry Andric 
32390b57cec5SDimitry Andric static void tracePick(GenericSchedulerBase::CandReason Reason, bool IsTop) {
32400b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Pick " << (IsTop ? "Top " : "Bot ")
32410b57cec5SDimitry Andric                     << GenericSchedulerBase::getReasonStr(Reason) << '\n');
32420b57cec5SDimitry Andric }
32430b57cec5SDimitry Andric 
32440b57cec5SDimitry Andric static void tracePick(const GenericSchedulerBase::SchedCandidate &Cand) {
32450b57cec5SDimitry Andric   tracePick(Cand.Reason, Cand.AtTop);
32460b57cec5SDimitry Andric }
32470b57cec5SDimitry Andric 
32480b57cec5SDimitry Andric void GenericScheduler::initialize(ScheduleDAGMI *dag) {
32490b57cec5SDimitry Andric   assert(dag->hasVRegLiveness() &&
32500b57cec5SDimitry Andric          "(PreRA)GenericScheduler needs vreg liveness");
32510b57cec5SDimitry Andric   DAG = static_cast<ScheduleDAGMILive*>(dag);
32520b57cec5SDimitry Andric   SchedModel = DAG->getSchedModel();
32530b57cec5SDimitry Andric   TRI = DAG->TRI;
32540b57cec5SDimitry Andric 
32555ffd83dbSDimitry Andric   if (RegionPolicy.ComputeDFSResult)
32565ffd83dbSDimitry Andric     DAG->computeDFSResult();
32575ffd83dbSDimitry Andric 
32580b57cec5SDimitry Andric   Rem.init(DAG, SchedModel);
32590b57cec5SDimitry Andric   Top.init(DAG, SchedModel, &Rem);
32600b57cec5SDimitry Andric   Bot.init(DAG, SchedModel, &Rem);
32610b57cec5SDimitry Andric 
32620b57cec5SDimitry Andric   // Initialize resource counts.
32630b57cec5SDimitry Andric 
32640b57cec5SDimitry Andric   // Initialize the HazardRecognizers. If itineraries don't exist, are empty, or
32650b57cec5SDimitry Andric   // are disabled, then these HazardRecs will be disabled.
32660b57cec5SDimitry Andric   const InstrItineraryData *Itin = SchedModel->getInstrItineraries();
32670b57cec5SDimitry Andric   if (!Top.HazardRec) {
3268*0fca6ea1SDimitry Andric     Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
32690b57cec5SDimitry Andric   }
32700b57cec5SDimitry Andric   if (!Bot.HazardRec) {
3271*0fca6ea1SDimitry Andric     Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
32720b57cec5SDimitry Andric   }
32730b57cec5SDimitry Andric   TopCand.SU = nullptr;
32740b57cec5SDimitry Andric   BotCand.SU = nullptr;
32750b57cec5SDimitry Andric }
32760b57cec5SDimitry Andric 
32770b57cec5SDimitry Andric /// Initialize the per-region scheduling policy.
32780b57cec5SDimitry Andric void GenericScheduler::initPolicy(MachineBasicBlock::iterator Begin,
32790b57cec5SDimitry Andric                                   MachineBasicBlock::iterator End,
32800b57cec5SDimitry Andric                                   unsigned NumRegionInstrs) {
32810b57cec5SDimitry Andric   const MachineFunction &MF = *Begin->getMF();
32820b57cec5SDimitry Andric   const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
32830b57cec5SDimitry Andric 
32840b57cec5SDimitry Andric   // Avoid setting up the register pressure tracker for small regions to save
32850b57cec5SDimitry Andric   // compile time. As a rough heuristic, only track pressure when the number of
3286*0fca6ea1SDimitry Andric   // schedulable instructions exceeds half the allocatable integer register file
3287*0fca6ea1SDimitry Andric   // that is the largest legal integer regiser type.
32880b57cec5SDimitry Andric   RegionPolicy.ShouldTrackPressure = true;
3289*0fca6ea1SDimitry Andric   for (unsigned VT = MVT::i64; VT > (unsigned)MVT::i1; --VT) {
32900b57cec5SDimitry Andric     MVT::SimpleValueType LegalIntVT = (MVT::SimpleValueType)VT;
32910b57cec5SDimitry Andric     if (TLI->isTypeLegal(LegalIntVT)) {
32920b57cec5SDimitry Andric       unsigned NIntRegs = Context->RegClassInfo->getNumAllocatableRegs(
32930b57cec5SDimitry Andric         TLI->getRegClassFor(LegalIntVT));
32940b57cec5SDimitry Andric       RegionPolicy.ShouldTrackPressure = NumRegionInstrs > (NIntRegs / 2);
3295*0fca6ea1SDimitry Andric       break;
32960b57cec5SDimitry Andric     }
32970b57cec5SDimitry Andric   }
32980b57cec5SDimitry Andric 
32990b57cec5SDimitry Andric   // For generic targets, we default to bottom-up, because it's simpler and more
33000b57cec5SDimitry Andric   // compile-time optimizations have been implemented in that direction.
33010b57cec5SDimitry Andric   RegionPolicy.OnlyBottomUp = true;
33020b57cec5SDimitry Andric 
33030b57cec5SDimitry Andric   // Allow the subtarget to override default policy.
33040b57cec5SDimitry Andric   MF.getSubtarget().overrideSchedPolicy(RegionPolicy, NumRegionInstrs);
33050b57cec5SDimitry Andric 
33060b57cec5SDimitry Andric   // After subtarget overrides, apply command line options.
33070b57cec5SDimitry Andric   if (!EnableRegPressure) {
33080b57cec5SDimitry Andric     RegionPolicy.ShouldTrackPressure = false;
33090b57cec5SDimitry Andric     RegionPolicy.ShouldTrackLaneMasks = false;
33100b57cec5SDimitry Andric   }
33110b57cec5SDimitry Andric 
33120b57cec5SDimitry Andric   // Check -misched-topdown/bottomup can force or unforce scheduling direction.
33130b57cec5SDimitry Andric   // e.g. -misched-bottomup=false allows scheduling in both directions.
33140b57cec5SDimitry Andric   assert((!ForceTopDown || !ForceBottomUp) &&
33150b57cec5SDimitry Andric          "-misched-topdown incompatible with -misched-bottomup");
33160b57cec5SDimitry Andric   if (ForceBottomUp.getNumOccurrences() > 0) {
33170b57cec5SDimitry Andric     RegionPolicy.OnlyBottomUp = ForceBottomUp;
33180b57cec5SDimitry Andric     if (RegionPolicy.OnlyBottomUp)
33190b57cec5SDimitry Andric       RegionPolicy.OnlyTopDown = false;
33200b57cec5SDimitry Andric   }
33210b57cec5SDimitry Andric   if (ForceTopDown.getNumOccurrences() > 0) {
33220b57cec5SDimitry Andric     RegionPolicy.OnlyTopDown = ForceTopDown;
33230b57cec5SDimitry Andric     if (RegionPolicy.OnlyTopDown)
33240b57cec5SDimitry Andric       RegionPolicy.OnlyBottomUp = false;
33250b57cec5SDimitry Andric   }
33260b57cec5SDimitry Andric }
33270b57cec5SDimitry Andric 
33280b57cec5SDimitry Andric void GenericScheduler::dumpPolicy() const {
33290b57cec5SDimitry Andric   // Cannot completely remove virtual function even in release mode.
33300b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
33310b57cec5SDimitry Andric   dbgs() << "GenericScheduler RegionPolicy: "
33320b57cec5SDimitry Andric          << " ShouldTrackPressure=" << RegionPolicy.ShouldTrackPressure
33330b57cec5SDimitry Andric          << " OnlyTopDown=" << RegionPolicy.OnlyTopDown
33340b57cec5SDimitry Andric          << " OnlyBottomUp=" << RegionPolicy.OnlyBottomUp
33350b57cec5SDimitry Andric          << "\n";
33360b57cec5SDimitry Andric #endif
33370b57cec5SDimitry Andric }
33380b57cec5SDimitry Andric 
33390b57cec5SDimitry Andric /// Set IsAcyclicLatencyLimited if the acyclic path is longer than the cyclic
33400b57cec5SDimitry Andric /// critical path by more cycles than it takes to drain the instruction buffer.
33410b57cec5SDimitry Andric /// We estimate an upper bounds on in-flight instructions as:
33420b57cec5SDimitry Andric ///
33430b57cec5SDimitry Andric /// CyclesPerIteration = max( CyclicPath, Loop-Resource-Height )
33440b57cec5SDimitry Andric /// InFlightIterations = AcyclicPath / CyclesPerIteration
33450b57cec5SDimitry Andric /// InFlightResources = InFlightIterations * LoopResources
33460b57cec5SDimitry Andric ///
33470b57cec5SDimitry Andric /// TODO: Check execution resources in addition to IssueCount.
33480b57cec5SDimitry Andric void GenericScheduler::checkAcyclicLatency() {
33490b57cec5SDimitry Andric   if (Rem.CyclicCritPath == 0 || Rem.CyclicCritPath >= Rem.CriticalPath)
33500b57cec5SDimitry Andric     return;
33510b57cec5SDimitry Andric 
33520b57cec5SDimitry Andric   // Scaled number of cycles per loop iteration.
33530b57cec5SDimitry Andric   unsigned IterCount =
33540b57cec5SDimitry Andric     std::max(Rem.CyclicCritPath * SchedModel->getLatencyFactor(),
33550b57cec5SDimitry Andric              Rem.RemIssueCount);
33560b57cec5SDimitry Andric   // Scaled acyclic critical path.
33570b57cec5SDimitry Andric   unsigned AcyclicCount = Rem.CriticalPath * SchedModel->getLatencyFactor();
33580b57cec5SDimitry Andric   // InFlightCount = (AcyclicPath / IterCycles) * InstrPerLoop
33590b57cec5SDimitry Andric   unsigned InFlightCount =
33600b57cec5SDimitry Andric     (AcyclicCount * Rem.RemIssueCount + IterCount-1) / IterCount;
33610b57cec5SDimitry Andric   unsigned BufferLimit =
33620b57cec5SDimitry Andric     SchedModel->getMicroOpBufferSize() * SchedModel->getMicroOpFactor();
33630b57cec5SDimitry Andric 
33640b57cec5SDimitry Andric   Rem.IsAcyclicLatencyLimited = InFlightCount > BufferLimit;
33650b57cec5SDimitry Andric 
33660b57cec5SDimitry Andric   LLVM_DEBUG(
33670b57cec5SDimitry Andric       dbgs() << "IssueCycles="
33680b57cec5SDimitry Andric              << Rem.RemIssueCount / SchedModel->getLatencyFactor() << "c "
33690b57cec5SDimitry Andric              << "IterCycles=" << IterCount / SchedModel->getLatencyFactor()
33700b57cec5SDimitry Andric              << "c NumIters=" << (AcyclicCount + IterCount - 1) / IterCount
33710b57cec5SDimitry Andric              << " InFlight=" << InFlightCount / SchedModel->getMicroOpFactor()
33720b57cec5SDimitry Andric              << "m BufferLim=" << SchedModel->getMicroOpBufferSize() << "m\n";
33730b57cec5SDimitry Andric       if (Rem.IsAcyclicLatencyLimited) dbgs() << "  ACYCLIC LATENCY LIMIT\n");
33740b57cec5SDimitry Andric }
33750b57cec5SDimitry Andric 
33760b57cec5SDimitry Andric void GenericScheduler::registerRoots() {
33770b57cec5SDimitry Andric   Rem.CriticalPath = DAG->ExitSU.getDepth();
33780b57cec5SDimitry Andric 
33790b57cec5SDimitry Andric   // Some roots may not feed into ExitSU. Check all of them in case.
33800b57cec5SDimitry Andric   for (const SUnit *SU : Bot.Available) {
33810b57cec5SDimitry Andric     if (SU->getDepth() > Rem.CriticalPath)
33820b57cec5SDimitry Andric       Rem.CriticalPath = SU->getDepth();
33830b57cec5SDimitry Andric   }
33840b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << '\n');
33850b57cec5SDimitry Andric   if (DumpCriticalPathLength) {
33860b57cec5SDimitry Andric     errs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << " \n";
33870b57cec5SDimitry Andric   }
33880b57cec5SDimitry Andric 
33890b57cec5SDimitry Andric   if (EnableCyclicPath && SchedModel->getMicroOpBufferSize() > 0) {
33900b57cec5SDimitry Andric     Rem.CyclicCritPath = DAG->computeCyclicCriticalPath();
33910b57cec5SDimitry Andric     checkAcyclicLatency();
33920b57cec5SDimitry Andric   }
33930b57cec5SDimitry Andric }
33940b57cec5SDimitry Andric 
33950b57cec5SDimitry Andric namespace llvm {
33960b57cec5SDimitry Andric bool tryPressure(const PressureChange &TryP,
33970b57cec5SDimitry Andric                  const PressureChange &CandP,
33980b57cec5SDimitry Andric                  GenericSchedulerBase::SchedCandidate &TryCand,
33990b57cec5SDimitry Andric                  GenericSchedulerBase::SchedCandidate &Cand,
34000b57cec5SDimitry Andric                  GenericSchedulerBase::CandReason Reason,
34010b57cec5SDimitry Andric                  const TargetRegisterInfo *TRI,
34020b57cec5SDimitry Andric                  const MachineFunction &MF) {
34030b57cec5SDimitry Andric   // If one candidate decreases and the other increases, go with it.
34040b57cec5SDimitry Andric   // Invalid candidates have UnitInc==0.
34050b57cec5SDimitry Andric   if (tryGreater(TryP.getUnitInc() < 0, CandP.getUnitInc() < 0, TryCand, Cand,
34060b57cec5SDimitry Andric                  Reason)) {
34070b57cec5SDimitry Andric     return true;
34080b57cec5SDimitry Andric   }
34090b57cec5SDimitry Andric   // Do not compare the magnitude of pressure changes between top and bottom
34100b57cec5SDimitry Andric   // boundary.
34110b57cec5SDimitry Andric   if (Cand.AtTop != TryCand.AtTop)
34120b57cec5SDimitry Andric     return false;
34130b57cec5SDimitry Andric 
34140b57cec5SDimitry Andric   // If both candidates affect the same set in the same boundary, go with the
34150b57cec5SDimitry Andric   // smallest increase.
34160b57cec5SDimitry Andric   unsigned TryPSet = TryP.getPSetOrMax();
34170b57cec5SDimitry Andric   unsigned CandPSet = CandP.getPSetOrMax();
34180b57cec5SDimitry Andric   if (TryPSet == CandPSet) {
34190b57cec5SDimitry Andric     return tryLess(TryP.getUnitInc(), CandP.getUnitInc(), TryCand, Cand,
34200b57cec5SDimitry Andric                    Reason);
34210b57cec5SDimitry Andric   }
34220b57cec5SDimitry Andric 
34230b57cec5SDimitry Andric   int TryRank = TryP.isValid() ? TRI->getRegPressureSetScore(MF, TryPSet) :
34240b57cec5SDimitry Andric                                  std::numeric_limits<int>::max();
34250b57cec5SDimitry Andric 
34260b57cec5SDimitry Andric   int CandRank = CandP.isValid() ? TRI->getRegPressureSetScore(MF, CandPSet) :
34270b57cec5SDimitry Andric                                    std::numeric_limits<int>::max();
34280b57cec5SDimitry Andric 
34290b57cec5SDimitry Andric   // If the candidates are decreasing pressure, reverse priority.
34300b57cec5SDimitry Andric   if (TryP.getUnitInc() < 0)
34310b57cec5SDimitry Andric     std::swap(TryRank, CandRank);
34320b57cec5SDimitry Andric   return tryGreater(TryRank, CandRank, TryCand, Cand, Reason);
34330b57cec5SDimitry Andric }
34340b57cec5SDimitry Andric 
34350b57cec5SDimitry Andric unsigned getWeakLeft(const SUnit *SU, bool isTop) {
34360b57cec5SDimitry Andric   return (isTop) ? SU->WeakPredsLeft : SU->WeakSuccsLeft;
34370b57cec5SDimitry Andric }
34380b57cec5SDimitry Andric 
34390b57cec5SDimitry Andric /// Minimize physical register live ranges. Regalloc wants them adjacent to
34400b57cec5SDimitry Andric /// their physreg def/use.
34410b57cec5SDimitry Andric ///
34420b57cec5SDimitry Andric /// FIXME: This is an unnecessary check on the critical path. Most are root/leaf
34430b57cec5SDimitry Andric /// copies which can be prescheduled. The rest (e.g. x86 MUL) could be bundled
34440b57cec5SDimitry Andric /// with the operation that produces or consumes the physreg. We'll do this when
34450b57cec5SDimitry Andric /// regalloc has support for parallel copies.
34460b57cec5SDimitry Andric int biasPhysReg(const SUnit *SU, bool isTop) {
34470b57cec5SDimitry Andric   const MachineInstr *MI = SU->getInstr();
34480b57cec5SDimitry Andric 
34490b57cec5SDimitry Andric   if (MI->isCopy()) {
34500b57cec5SDimitry Andric     unsigned ScheduledOper = isTop ? 1 : 0;
34510b57cec5SDimitry Andric     unsigned UnscheduledOper = isTop ? 0 : 1;
34520b57cec5SDimitry Andric     // If we have already scheduled the physreg produce/consumer, immediately
34530b57cec5SDimitry Andric     // schedule the copy.
3454bdd1243dSDimitry Andric     if (MI->getOperand(ScheduledOper).getReg().isPhysical())
34550b57cec5SDimitry Andric       return 1;
34560b57cec5SDimitry Andric     // If the physreg is at the boundary, defer it. Otherwise schedule it
34570b57cec5SDimitry Andric     // immediately to free the dependent. We can hoist the copy later.
34580b57cec5SDimitry Andric     bool AtBoundary = isTop ? !SU->NumSuccsLeft : !SU->NumPredsLeft;
3459bdd1243dSDimitry Andric     if (MI->getOperand(UnscheduledOper).getReg().isPhysical())
34600b57cec5SDimitry Andric       return AtBoundary ? -1 : 1;
34610b57cec5SDimitry Andric   }
34620b57cec5SDimitry Andric 
34630b57cec5SDimitry Andric   if (MI->isMoveImmediate()) {
34640b57cec5SDimitry Andric     // If we have a move immediate and all successors have been assigned, bias
34650b57cec5SDimitry Andric     // towards scheduling this later. Make sure all register defs are to
34660b57cec5SDimitry Andric     // physical registers.
34670b57cec5SDimitry Andric     bool DoBias = true;
34680b57cec5SDimitry Andric     for (const MachineOperand &Op : MI->defs()) {
3469bdd1243dSDimitry Andric       if (Op.isReg() && !Op.getReg().isPhysical()) {
34700b57cec5SDimitry Andric         DoBias = false;
34710b57cec5SDimitry Andric         break;
34720b57cec5SDimitry Andric       }
34730b57cec5SDimitry Andric     }
34740b57cec5SDimitry Andric 
34750b57cec5SDimitry Andric     if (DoBias)
34760b57cec5SDimitry Andric       return isTop ? -1 : 1;
34770b57cec5SDimitry Andric   }
34780b57cec5SDimitry Andric 
34790b57cec5SDimitry Andric   return 0;
34800b57cec5SDimitry Andric }
34810b57cec5SDimitry Andric } // end namespace llvm
34820b57cec5SDimitry Andric 
34830b57cec5SDimitry Andric void GenericScheduler::initCandidate(SchedCandidate &Cand, SUnit *SU,
34840b57cec5SDimitry Andric                                      bool AtTop,
34850b57cec5SDimitry Andric                                      const RegPressureTracker &RPTracker,
34860b57cec5SDimitry Andric                                      RegPressureTracker &TempTracker) {
34870b57cec5SDimitry Andric   Cand.SU = SU;
34880b57cec5SDimitry Andric   Cand.AtTop = AtTop;
34890b57cec5SDimitry Andric   if (DAG->isTrackingPressure()) {
34900b57cec5SDimitry Andric     if (AtTop) {
34910b57cec5SDimitry Andric       TempTracker.getMaxDownwardPressureDelta(
34920b57cec5SDimitry Andric         Cand.SU->getInstr(),
34930b57cec5SDimitry Andric         Cand.RPDelta,
34940b57cec5SDimitry Andric         DAG->getRegionCriticalPSets(),
34950b57cec5SDimitry Andric         DAG->getRegPressure().MaxSetPressure);
34960b57cec5SDimitry Andric     } else {
34970b57cec5SDimitry Andric       if (VerifyScheduling) {
34980b57cec5SDimitry Andric         TempTracker.getMaxUpwardPressureDelta(
34990b57cec5SDimitry Andric           Cand.SU->getInstr(),
35000b57cec5SDimitry Andric           &DAG->getPressureDiff(Cand.SU),
35010b57cec5SDimitry Andric           Cand.RPDelta,
35020b57cec5SDimitry Andric           DAG->getRegionCriticalPSets(),
35030b57cec5SDimitry Andric           DAG->getRegPressure().MaxSetPressure);
35040b57cec5SDimitry Andric       } else {
35050b57cec5SDimitry Andric         RPTracker.getUpwardPressureDelta(
35060b57cec5SDimitry Andric           Cand.SU->getInstr(),
35070b57cec5SDimitry Andric           DAG->getPressureDiff(Cand.SU),
35080b57cec5SDimitry Andric           Cand.RPDelta,
35090b57cec5SDimitry Andric           DAG->getRegionCriticalPSets(),
35100b57cec5SDimitry Andric           DAG->getRegPressure().MaxSetPressure);
35110b57cec5SDimitry Andric       }
35120b57cec5SDimitry Andric     }
35130b57cec5SDimitry Andric   }
35140b57cec5SDimitry Andric   LLVM_DEBUG(if (Cand.RPDelta.Excess.isValid()) dbgs()
35150b57cec5SDimitry Andric              << "  Try  SU(" << Cand.SU->NodeNum << ") "
35160b57cec5SDimitry Andric              << TRI->getRegPressureSetName(Cand.RPDelta.Excess.getPSet()) << ":"
35170b57cec5SDimitry Andric              << Cand.RPDelta.Excess.getUnitInc() << "\n");
35180b57cec5SDimitry Andric }
35190b57cec5SDimitry Andric 
35200b57cec5SDimitry Andric /// Apply a set of heuristics to a new candidate. Heuristics are currently
35210b57cec5SDimitry Andric /// hierarchical. This may be more efficient than a graduated cost model because
35220b57cec5SDimitry Andric /// we don't need to evaluate all aspects of the model for each node in the
35230b57cec5SDimitry Andric /// queue. But it's really done to make the heuristics easier to debug and
35240b57cec5SDimitry Andric /// statistically analyze.
35250b57cec5SDimitry Andric ///
35260b57cec5SDimitry Andric /// \param Cand provides the policy and current best candidate.
35270b57cec5SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
35280b57cec5SDimitry Andric /// \param Zone describes the scheduled zone that we are extending, or nullptr
3529fe6060f1SDimitry Andric ///             if Cand is from a different zone than TryCand.
3530fe6060f1SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
3531fe6060f1SDimitry Andric bool GenericScheduler::tryCandidate(SchedCandidate &Cand,
35320b57cec5SDimitry Andric                                     SchedCandidate &TryCand,
35330b57cec5SDimitry Andric                                     SchedBoundary *Zone) const {
35340b57cec5SDimitry Andric   // Initialize the candidate if needed.
35350b57cec5SDimitry Andric   if (!Cand.isValid()) {
35360b57cec5SDimitry Andric     TryCand.Reason = NodeOrder;
3537fe6060f1SDimitry Andric     return true;
35380b57cec5SDimitry Andric   }
35390b57cec5SDimitry Andric 
35400b57cec5SDimitry Andric   // Bias PhysReg Defs and copies to their uses and defined respectively.
35410b57cec5SDimitry Andric   if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
35420b57cec5SDimitry Andric                  biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
3543fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
35440b57cec5SDimitry Andric 
35450b57cec5SDimitry Andric   // Avoid exceeding the target's limit.
35460b57cec5SDimitry Andric   if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.Excess,
35470b57cec5SDimitry Andric                                                Cand.RPDelta.Excess,
35480b57cec5SDimitry Andric                                                TryCand, Cand, RegExcess, TRI,
35490b57cec5SDimitry Andric                                                DAG->MF))
3550fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
35510b57cec5SDimitry Andric 
35520b57cec5SDimitry Andric   // Avoid increasing the max critical pressure in the scheduled region.
35530b57cec5SDimitry Andric   if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CriticalMax,
35540b57cec5SDimitry Andric                                                Cand.RPDelta.CriticalMax,
35550b57cec5SDimitry Andric                                                TryCand, Cand, RegCritical, TRI,
35560b57cec5SDimitry Andric                                                DAG->MF))
3557fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
35580b57cec5SDimitry Andric 
35590b57cec5SDimitry Andric   // We only compare a subset of features when comparing nodes between
35600b57cec5SDimitry Andric   // Top and Bottom boundary. Some properties are simply incomparable, in many
35610b57cec5SDimitry Andric   // other instances we should only override the other boundary if something
35620b57cec5SDimitry Andric   // is a clear good pick on one boundary. Skip heuristics that are more
35630b57cec5SDimitry Andric   // "tie-breaking" in nature.
35640b57cec5SDimitry Andric   bool SameBoundary = Zone != nullptr;
35650b57cec5SDimitry Andric   if (SameBoundary) {
35660b57cec5SDimitry Andric     // For loops that are acyclic path limited, aggressively schedule for
35670b57cec5SDimitry Andric     // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
35680b57cec5SDimitry Andric     // heuristics to take precedence.
35690b57cec5SDimitry Andric     if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
35700b57cec5SDimitry Andric         tryLatency(TryCand, Cand, *Zone))
3571fe6060f1SDimitry Andric       return TryCand.Reason != NoCand;
35720b57cec5SDimitry Andric 
35730b57cec5SDimitry Andric     // Prioritize instructions that read unbuffered resources by stall cycles.
35740b57cec5SDimitry Andric     if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
35750b57cec5SDimitry Andric                 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
3576fe6060f1SDimitry Andric       return TryCand.Reason != NoCand;
35770b57cec5SDimitry Andric   }
35780b57cec5SDimitry Andric 
35790b57cec5SDimitry Andric   // Keep clustered nodes together to encourage downstream peephole
35800b57cec5SDimitry Andric   // optimizations which may reduce resource requirements.
35810b57cec5SDimitry Andric   //
35820b57cec5SDimitry Andric   // This is a best effort to set things up for a post-RA pass. Optimizations
35830b57cec5SDimitry Andric   // like generating loads of multiple registers should ideally be done within
35840b57cec5SDimitry Andric   // the scheduler pass by combining the loads during DAG postprocessing.
35850b57cec5SDimitry Andric   const SUnit *CandNextClusterSU =
35860b57cec5SDimitry Andric     Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
35870b57cec5SDimitry Andric   const SUnit *TryCandNextClusterSU =
35880b57cec5SDimitry Andric     TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
35890b57cec5SDimitry Andric   if (tryGreater(TryCand.SU == TryCandNextClusterSU,
35900b57cec5SDimitry Andric                  Cand.SU == CandNextClusterSU,
35910b57cec5SDimitry Andric                  TryCand, Cand, Cluster))
3592fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
35930b57cec5SDimitry Andric 
35940b57cec5SDimitry Andric   if (SameBoundary) {
35950b57cec5SDimitry Andric     // Weak edges are for clustering and other constraints.
35960b57cec5SDimitry Andric     if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
35970b57cec5SDimitry Andric                 getWeakLeft(Cand.SU, Cand.AtTop),
35980b57cec5SDimitry Andric                 TryCand, Cand, Weak))
3599fe6060f1SDimitry Andric       return TryCand.Reason != NoCand;
36000b57cec5SDimitry Andric   }
36010b57cec5SDimitry Andric 
36020b57cec5SDimitry Andric   // Avoid increasing the max pressure of the entire region.
36030b57cec5SDimitry Andric   if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CurrentMax,
36040b57cec5SDimitry Andric                                                Cand.RPDelta.CurrentMax,
36050b57cec5SDimitry Andric                                                TryCand, Cand, RegMax, TRI,
36060b57cec5SDimitry Andric                                                DAG->MF))
3607fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
36080b57cec5SDimitry Andric 
36090b57cec5SDimitry Andric   if (SameBoundary) {
36100b57cec5SDimitry Andric     // Avoid critical resource consumption and balance the schedule.
36110b57cec5SDimitry Andric     TryCand.initResourceDelta(DAG, SchedModel);
36120b57cec5SDimitry Andric     if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
36130b57cec5SDimitry Andric                 TryCand, Cand, ResourceReduce))
3614fe6060f1SDimitry Andric       return TryCand.Reason != NoCand;
36150b57cec5SDimitry Andric     if (tryGreater(TryCand.ResDelta.DemandedResources,
36160b57cec5SDimitry Andric                    Cand.ResDelta.DemandedResources,
36170b57cec5SDimitry Andric                    TryCand, Cand, ResourceDemand))
3618fe6060f1SDimitry Andric       return TryCand.Reason != NoCand;
36190b57cec5SDimitry Andric 
36200b57cec5SDimitry Andric     // Avoid serializing long latency dependence chains.
36210b57cec5SDimitry Andric     // For acyclic path limited loops, latency was already checked above.
36220b57cec5SDimitry Andric     if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
36230b57cec5SDimitry Andric         !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
3624fe6060f1SDimitry Andric       return TryCand.Reason != NoCand;
36250b57cec5SDimitry Andric 
36260b57cec5SDimitry Andric     // Fall through to original instruction order.
36270b57cec5SDimitry Andric     if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum)
36280b57cec5SDimitry Andric         || (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
36290b57cec5SDimitry Andric       TryCand.Reason = NodeOrder;
3630fe6060f1SDimitry Andric       return true;
36310b57cec5SDimitry Andric     }
36320b57cec5SDimitry Andric   }
3633fe6060f1SDimitry Andric 
3634fe6060f1SDimitry Andric   return false;
36350b57cec5SDimitry Andric }
36360b57cec5SDimitry Andric 
36370b57cec5SDimitry Andric /// Pick the best candidate from the queue.
36380b57cec5SDimitry Andric ///
36390b57cec5SDimitry Andric /// TODO: getMaxPressureDelta results can be mostly cached for each SUnit during
36400b57cec5SDimitry Andric /// DAG building. To adjust for the current scheduling location we need to
36410b57cec5SDimitry Andric /// maintain the number of vreg uses remaining to be top-scheduled.
36420b57cec5SDimitry Andric void GenericScheduler::pickNodeFromQueue(SchedBoundary &Zone,
36430b57cec5SDimitry Andric                                          const CandPolicy &ZonePolicy,
36440b57cec5SDimitry Andric                                          const RegPressureTracker &RPTracker,
36450b57cec5SDimitry Andric                                          SchedCandidate &Cand) {
36460b57cec5SDimitry Andric   // getMaxPressureDelta temporarily modifies the tracker.
36470b57cec5SDimitry Andric   RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);
36480b57cec5SDimitry Andric 
36490b57cec5SDimitry Andric   ReadyQueue &Q = Zone.Available;
36500b57cec5SDimitry Andric   for (SUnit *SU : Q) {
36510b57cec5SDimitry Andric 
36520b57cec5SDimitry Andric     SchedCandidate TryCand(ZonePolicy);
36530b57cec5SDimitry Andric     initCandidate(TryCand, SU, Zone.isTop(), RPTracker, TempTracker);
36540b57cec5SDimitry Andric     // Pass SchedBoundary only when comparing nodes from the same boundary.
36550b57cec5SDimitry Andric     SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
3656fe6060f1SDimitry Andric     if (tryCandidate(Cand, TryCand, ZoneArg)) {
36570b57cec5SDimitry Andric       // Initialize resource delta if needed in case future heuristics query it.
36580b57cec5SDimitry Andric       if (TryCand.ResDelta == SchedResourceDelta())
36590b57cec5SDimitry Andric         TryCand.initResourceDelta(DAG, SchedModel);
36600b57cec5SDimitry Andric       Cand.setBest(TryCand);
36610b57cec5SDimitry Andric       LLVM_DEBUG(traceCandidate(Cand));
36620b57cec5SDimitry Andric     }
36630b57cec5SDimitry Andric   }
36640b57cec5SDimitry Andric }
36650b57cec5SDimitry Andric 
36660b57cec5SDimitry Andric /// Pick the best candidate node from either the top or bottom queue.
36670b57cec5SDimitry Andric SUnit *GenericScheduler::pickNodeBidirectional(bool &IsTopNode) {
36680b57cec5SDimitry Andric   // Schedule as far as possible in the direction of no choice. This is most
36690b57cec5SDimitry Andric   // efficient, but also provides the best heuristics for CriticalPSets.
36700b57cec5SDimitry Andric   if (SUnit *SU = Bot.pickOnlyChoice()) {
36710b57cec5SDimitry Andric     IsTopNode = false;
36720b57cec5SDimitry Andric     tracePick(Only1, false);
36730b57cec5SDimitry Andric     return SU;
36740b57cec5SDimitry Andric   }
36750b57cec5SDimitry Andric   if (SUnit *SU = Top.pickOnlyChoice()) {
36760b57cec5SDimitry Andric     IsTopNode = true;
36770b57cec5SDimitry Andric     tracePick(Only1, true);
36780b57cec5SDimitry Andric     return SU;
36790b57cec5SDimitry Andric   }
36800b57cec5SDimitry Andric   // Set the bottom-up policy based on the state of the current bottom zone and
36810b57cec5SDimitry Andric   // the instructions outside the zone, including the top zone.
36820b57cec5SDimitry Andric   CandPolicy BotPolicy;
36830b57cec5SDimitry Andric   setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
36840b57cec5SDimitry Andric   // Set the top-down policy based on the state of the current top zone and
36850b57cec5SDimitry Andric   // the instructions outside the zone, including the bottom zone.
36860b57cec5SDimitry Andric   CandPolicy TopPolicy;
36870b57cec5SDimitry Andric   setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
36880b57cec5SDimitry Andric 
36890b57cec5SDimitry Andric   // See if BotCand is still valid (because we previously scheduled from Top).
36900b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
36910b57cec5SDimitry Andric   if (!BotCand.isValid() || BotCand.SU->isScheduled ||
36920b57cec5SDimitry Andric       BotCand.Policy != BotPolicy) {
36930b57cec5SDimitry Andric     BotCand.reset(CandPolicy());
36940b57cec5SDimitry Andric     pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand);
36950b57cec5SDimitry Andric     assert(BotCand.Reason != NoCand && "failed to find the first candidate");
36960b57cec5SDimitry Andric   } else {
36970b57cec5SDimitry Andric     LLVM_DEBUG(traceCandidate(BotCand));
36980b57cec5SDimitry Andric #ifndef NDEBUG
36990b57cec5SDimitry Andric     if (VerifyScheduling) {
37000b57cec5SDimitry Andric       SchedCandidate TCand;
37010b57cec5SDimitry Andric       TCand.reset(CandPolicy());
37020b57cec5SDimitry Andric       pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand);
37030b57cec5SDimitry Andric       assert(TCand.SU == BotCand.SU &&
37040b57cec5SDimitry Andric              "Last pick result should correspond to re-picking right now");
37050b57cec5SDimitry Andric     }
37060b57cec5SDimitry Andric #endif
37070b57cec5SDimitry Andric   }
37080b57cec5SDimitry Andric 
37090b57cec5SDimitry Andric   // Check if the top Q has a better candidate.
37100b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Top:\n");
37110b57cec5SDimitry Andric   if (!TopCand.isValid() || TopCand.SU->isScheduled ||
37120b57cec5SDimitry Andric       TopCand.Policy != TopPolicy) {
37130b57cec5SDimitry Andric     TopCand.reset(CandPolicy());
37140b57cec5SDimitry Andric     pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand);
37150b57cec5SDimitry Andric     assert(TopCand.Reason != NoCand && "failed to find the first candidate");
37160b57cec5SDimitry Andric   } else {
37170b57cec5SDimitry Andric     LLVM_DEBUG(traceCandidate(TopCand));
37180b57cec5SDimitry Andric #ifndef NDEBUG
37190b57cec5SDimitry Andric     if (VerifyScheduling) {
37200b57cec5SDimitry Andric       SchedCandidate TCand;
37210b57cec5SDimitry Andric       TCand.reset(CandPolicy());
37220b57cec5SDimitry Andric       pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand);
37230b57cec5SDimitry Andric       assert(TCand.SU == TopCand.SU &&
37240b57cec5SDimitry Andric              "Last pick result should correspond to re-picking right now");
37250b57cec5SDimitry Andric     }
37260b57cec5SDimitry Andric #endif
37270b57cec5SDimitry Andric   }
37280b57cec5SDimitry Andric 
37290b57cec5SDimitry Andric   // Pick best from BotCand and TopCand.
37300b57cec5SDimitry Andric   assert(BotCand.isValid());
37310b57cec5SDimitry Andric   assert(TopCand.isValid());
37320b57cec5SDimitry Andric   SchedCandidate Cand = BotCand;
37330b57cec5SDimitry Andric   TopCand.Reason = NoCand;
3734fe6060f1SDimitry Andric   if (tryCandidate(Cand, TopCand, nullptr)) {
37350b57cec5SDimitry Andric     Cand.setBest(TopCand);
37360b57cec5SDimitry Andric     LLVM_DEBUG(traceCandidate(Cand));
37370b57cec5SDimitry Andric   }
37380b57cec5SDimitry Andric 
37390b57cec5SDimitry Andric   IsTopNode = Cand.AtTop;
37400b57cec5SDimitry Andric   tracePick(Cand);
37410b57cec5SDimitry Andric   return Cand.SU;
37420b57cec5SDimitry Andric }
37430b57cec5SDimitry Andric 
37440b57cec5SDimitry Andric /// Pick the best node to balance the schedule. Implements MachineSchedStrategy.
37450b57cec5SDimitry Andric SUnit *GenericScheduler::pickNode(bool &IsTopNode) {
37460b57cec5SDimitry Andric   if (DAG->top() == DAG->bottom()) {
37470b57cec5SDimitry Andric     assert(Top.Available.empty() && Top.Pending.empty() &&
37480b57cec5SDimitry Andric            Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
37490b57cec5SDimitry Andric     return nullptr;
37500b57cec5SDimitry Andric   }
37510b57cec5SDimitry Andric   SUnit *SU;
37520b57cec5SDimitry Andric   do {
37530b57cec5SDimitry Andric     if (RegionPolicy.OnlyTopDown) {
37540b57cec5SDimitry Andric       SU = Top.pickOnlyChoice();
37550b57cec5SDimitry Andric       if (!SU) {
37560b57cec5SDimitry Andric         CandPolicy NoPolicy;
37570b57cec5SDimitry Andric         TopCand.reset(NoPolicy);
37580b57cec5SDimitry Andric         pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand);
37590b57cec5SDimitry Andric         assert(TopCand.Reason != NoCand && "failed to find a candidate");
37600b57cec5SDimitry Andric         tracePick(TopCand);
37610b57cec5SDimitry Andric         SU = TopCand.SU;
37620b57cec5SDimitry Andric       }
37630b57cec5SDimitry Andric       IsTopNode = true;
37640b57cec5SDimitry Andric     } else if (RegionPolicy.OnlyBottomUp) {
37650b57cec5SDimitry Andric       SU = Bot.pickOnlyChoice();
37660b57cec5SDimitry Andric       if (!SU) {
37670b57cec5SDimitry Andric         CandPolicy NoPolicy;
37680b57cec5SDimitry Andric         BotCand.reset(NoPolicy);
37690b57cec5SDimitry Andric         pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand);
37700b57cec5SDimitry Andric         assert(BotCand.Reason != NoCand && "failed to find a candidate");
37710b57cec5SDimitry Andric         tracePick(BotCand);
37720b57cec5SDimitry Andric         SU = BotCand.SU;
37730b57cec5SDimitry Andric       }
37740b57cec5SDimitry Andric       IsTopNode = false;
37750b57cec5SDimitry Andric     } else {
37760b57cec5SDimitry Andric       SU = pickNodeBidirectional(IsTopNode);
37770b57cec5SDimitry Andric     }
37780b57cec5SDimitry Andric   } while (SU->isScheduled);
37790b57cec5SDimitry Andric 
3780*0fca6ea1SDimitry Andric   // If IsTopNode, then SU is in Top.Available and must be removed. Otherwise,
3781*0fca6ea1SDimitry Andric   // if isTopReady(), then SU is in either Top.Available or Top.Pending.
3782*0fca6ea1SDimitry Andric   // If !IsTopNode, then SU is in Bot.Available and must be removed. Otherwise,
3783*0fca6ea1SDimitry Andric   // if isBottomReady(), then SU is in either Bot.Available or Bot.Pending.
3784*0fca6ea1SDimitry Andric   //
3785*0fca6ea1SDimitry Andric   // It is coincidental when !IsTopNode && isTopReady or when IsTopNode &&
3786*0fca6ea1SDimitry Andric   // isBottomReady. That is, it didn't factor into the decision to choose SU
3787*0fca6ea1SDimitry Andric   // because it isTopReady or isBottomReady, respectively. In fact, if the
3788*0fca6ea1SDimitry Andric   // RegionPolicy is OnlyTopDown or OnlyBottomUp, then the Bot queues and Top
3789*0fca6ea1SDimitry Andric   // queues respectivley contain the original roots and don't get updated when
3790*0fca6ea1SDimitry Andric   // picking a node. So if SU isTopReady on a OnlyBottomUp pick, then it was
3791*0fca6ea1SDimitry Andric   // because we schduled everything but the top roots. Conversley, if SU
3792*0fca6ea1SDimitry Andric   // isBottomReady on OnlyTopDown, then it was because we scheduled everything
3793*0fca6ea1SDimitry Andric   // but the bottom roots. If its in a queue even coincidentally, it should be
3794*0fca6ea1SDimitry Andric   // removed so it does not get re-picked in a subsequent pickNode call.
37950b57cec5SDimitry Andric   if (SU->isTopReady())
37960b57cec5SDimitry Andric     Top.removeReady(SU);
37970b57cec5SDimitry Andric   if (SU->isBottomReady())
37980b57cec5SDimitry Andric     Bot.removeReady(SU);
37990b57cec5SDimitry Andric 
38000b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
38010b57cec5SDimitry Andric                     << *SU->getInstr());
38020b57cec5SDimitry Andric   return SU;
38030b57cec5SDimitry Andric }
38040b57cec5SDimitry Andric 
38050b57cec5SDimitry Andric void GenericScheduler::reschedulePhysReg(SUnit *SU, bool isTop) {
38060b57cec5SDimitry Andric   MachineBasicBlock::iterator InsertPos = SU->getInstr();
38070b57cec5SDimitry Andric   if (!isTop)
38080b57cec5SDimitry Andric     ++InsertPos;
38090b57cec5SDimitry Andric   SmallVectorImpl<SDep> &Deps = isTop ? SU->Preds : SU->Succs;
38100b57cec5SDimitry Andric 
38110b57cec5SDimitry Andric   // Find already scheduled copies with a single physreg dependence and move
38120b57cec5SDimitry Andric   // them just above the scheduled instruction.
38130b57cec5SDimitry Andric   for (SDep &Dep : Deps) {
38148bcb0991SDimitry Andric     if (Dep.getKind() != SDep::Data ||
38158bcb0991SDimitry Andric         !Register::isPhysicalRegister(Dep.getReg()))
38160b57cec5SDimitry Andric       continue;
38170b57cec5SDimitry Andric     SUnit *DepSU = Dep.getSUnit();
38180b57cec5SDimitry Andric     if (isTop ? DepSU->Succs.size() > 1 : DepSU->Preds.size() > 1)
38190b57cec5SDimitry Andric       continue;
38200b57cec5SDimitry Andric     MachineInstr *Copy = DepSU->getInstr();
38210b57cec5SDimitry Andric     if (!Copy->isCopy() && !Copy->isMoveImmediate())
38220b57cec5SDimitry Andric       continue;
38230b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  Rescheduling physreg copy ";
38240b57cec5SDimitry Andric                DAG->dumpNode(*Dep.getSUnit()));
38250b57cec5SDimitry Andric     DAG->moveInstruction(Copy, InsertPos);
38260b57cec5SDimitry Andric   }
38270b57cec5SDimitry Andric }
38280b57cec5SDimitry Andric 
38290b57cec5SDimitry Andric /// Update the scheduler's state after scheduling a node. This is the same node
38300b57cec5SDimitry Andric /// that was just returned by pickNode(). However, ScheduleDAGMILive needs to
38310b57cec5SDimitry Andric /// update it's state based on the current cycle before MachineSchedStrategy
38320b57cec5SDimitry Andric /// does.
38330b57cec5SDimitry Andric ///
38340b57cec5SDimitry Andric /// FIXME: Eventually, we may bundle physreg copies rather than rescheduling
38350b57cec5SDimitry Andric /// them here. See comments in biasPhysReg.
38360b57cec5SDimitry Andric void GenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
38370b57cec5SDimitry Andric   if (IsTopNode) {
38380b57cec5SDimitry Andric     SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle());
38390b57cec5SDimitry Andric     Top.bumpNode(SU);
38400b57cec5SDimitry Andric     if (SU->hasPhysRegUses)
38410b57cec5SDimitry Andric       reschedulePhysReg(SU, true);
38420b57cec5SDimitry Andric   } else {
38430b57cec5SDimitry Andric     SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle());
38440b57cec5SDimitry Andric     Bot.bumpNode(SU);
38450b57cec5SDimitry Andric     if (SU->hasPhysRegDefs)
38460b57cec5SDimitry Andric       reschedulePhysReg(SU, false);
38470b57cec5SDimitry Andric   }
38480b57cec5SDimitry Andric }
38490b57cec5SDimitry Andric 
38500b57cec5SDimitry Andric /// Create the standard converging machine scheduler. This will be used as the
38510b57cec5SDimitry Andric /// default scheduler if the target does not set a default.
38520b57cec5SDimitry Andric ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) {
38530b57cec5SDimitry Andric   ScheduleDAGMILive *DAG =
38548bcb0991SDimitry Andric       new ScheduleDAGMILive(C, std::make_unique<GenericScheduler>(C));
38550b57cec5SDimitry Andric   // Register DAG post-processors.
38560b57cec5SDimitry Andric   //
38570b57cec5SDimitry Andric   // FIXME: extend the mutation API to allow earlier mutations to instantiate
38580b57cec5SDimitry Andric   // data and pass it to later mutations. Have a single mutation that gathers
38590b57cec5SDimitry Andric   // the interesting nodes in one pass.
38600b57cec5SDimitry Andric   DAG->addMutation(createCopyConstrainDAGMutation(DAG->TII, DAG->TRI));
3861*0fca6ea1SDimitry Andric 
3862*0fca6ea1SDimitry Andric   const TargetSubtargetInfo &STI = C->MF->getSubtarget();
3863*0fca6ea1SDimitry Andric   // Add MacroFusion mutation if fusions are not empty.
3864*0fca6ea1SDimitry Andric   const auto &MacroFusions = STI.getMacroFusions();
3865*0fca6ea1SDimitry Andric   if (!MacroFusions.empty())
3866*0fca6ea1SDimitry Andric     DAG->addMutation(createMacroFusionDAGMutation(MacroFusions));
38670b57cec5SDimitry Andric   return DAG;
38680b57cec5SDimitry Andric }
38690b57cec5SDimitry Andric 
3870e8d8bef9SDimitry Andric static ScheduleDAGInstrs *createConvergingSched(MachineSchedContext *C) {
38710b57cec5SDimitry Andric   return createGenericSchedLive(C);
38720b57cec5SDimitry Andric }
38730b57cec5SDimitry Andric 
38740b57cec5SDimitry Andric static MachineSchedRegistry
38750b57cec5SDimitry Andric GenericSchedRegistry("converge", "Standard converging scheduler.",
3876e8d8bef9SDimitry Andric                      createConvergingSched);
38770b57cec5SDimitry Andric 
38780b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
38790b57cec5SDimitry Andric // PostGenericScheduler - Generic PostRA implementation of MachineSchedStrategy.
38800b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
38810b57cec5SDimitry Andric 
38820b57cec5SDimitry Andric void PostGenericScheduler::initialize(ScheduleDAGMI *Dag) {
38830b57cec5SDimitry Andric   DAG = Dag;
38840b57cec5SDimitry Andric   SchedModel = DAG->getSchedModel();
38850b57cec5SDimitry Andric   TRI = DAG->TRI;
38860b57cec5SDimitry Andric 
38870b57cec5SDimitry Andric   Rem.init(DAG, SchedModel);
38880b57cec5SDimitry Andric   Top.init(DAG, SchedModel, &Rem);
3889*0fca6ea1SDimitry Andric   Bot.init(DAG, SchedModel, &Rem);
38900b57cec5SDimitry Andric 
38910b57cec5SDimitry Andric   // Initialize the HazardRecognizers. If itineraries don't exist, are empty,
38920b57cec5SDimitry Andric   // or are disabled, then these HazardRecs will be disabled.
38930b57cec5SDimitry Andric   const InstrItineraryData *Itin = SchedModel->getInstrItineraries();
38940b57cec5SDimitry Andric   if (!Top.HazardRec) {
3895*0fca6ea1SDimitry Andric     Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
3896*0fca6ea1SDimitry Andric   }
3897*0fca6ea1SDimitry Andric   if (!Bot.HazardRec) {
3898*0fca6ea1SDimitry Andric     Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
3899*0fca6ea1SDimitry Andric   }
3900*0fca6ea1SDimitry Andric }
3901*0fca6ea1SDimitry Andric 
3902*0fca6ea1SDimitry Andric void PostGenericScheduler::initPolicy(MachineBasicBlock::iterator Begin,
3903*0fca6ea1SDimitry Andric                                       MachineBasicBlock::iterator End,
3904*0fca6ea1SDimitry Andric                                       unsigned NumRegionInstrs) {
3905*0fca6ea1SDimitry Andric   if (PostRADirection == MISchedPostRASched::TopDown) {
3906*0fca6ea1SDimitry Andric     RegionPolicy.OnlyTopDown = true;
3907*0fca6ea1SDimitry Andric     RegionPolicy.OnlyBottomUp = false;
3908*0fca6ea1SDimitry Andric   } else if (PostRADirection == MISchedPostRASched::BottomUp) {
3909*0fca6ea1SDimitry Andric     RegionPolicy.OnlyTopDown = false;
3910*0fca6ea1SDimitry Andric     RegionPolicy.OnlyBottomUp = true;
3911*0fca6ea1SDimitry Andric   } else if (PostRADirection == MISchedPostRASched::Bidirectional) {
3912*0fca6ea1SDimitry Andric     RegionPolicy.OnlyBottomUp = false;
3913*0fca6ea1SDimitry Andric     RegionPolicy.OnlyTopDown = false;
39140b57cec5SDimitry Andric   }
39150b57cec5SDimitry Andric }
39160b57cec5SDimitry Andric 
39170b57cec5SDimitry Andric void PostGenericScheduler::registerRoots() {
39180b57cec5SDimitry Andric   Rem.CriticalPath = DAG->ExitSU.getDepth();
39190b57cec5SDimitry Andric 
39200b57cec5SDimitry Andric   // Some roots may not feed into ExitSU. Check all of them in case.
3921*0fca6ea1SDimitry Andric   for (const SUnit *SU : Bot.Available) {
39220b57cec5SDimitry Andric     if (SU->getDepth() > Rem.CriticalPath)
39230b57cec5SDimitry Andric       Rem.CriticalPath = SU->getDepth();
39240b57cec5SDimitry Andric   }
39250b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Critical Path: (PGS-RR) " << Rem.CriticalPath << '\n');
39260b57cec5SDimitry Andric   if (DumpCriticalPathLength) {
39270b57cec5SDimitry Andric     errs() << "Critical Path(PGS-RR ): " << Rem.CriticalPath << " \n";
39280b57cec5SDimitry Andric   }
39290b57cec5SDimitry Andric }
39300b57cec5SDimitry Andric 
39310b57cec5SDimitry Andric /// Apply a set of heuristics to a new candidate for PostRA scheduling.
39320b57cec5SDimitry Andric ///
39330b57cec5SDimitry Andric /// \param Cand provides the policy and current best candidate.
39340b57cec5SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
3935fe6060f1SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
3936fe6060f1SDimitry Andric bool PostGenericScheduler::tryCandidate(SchedCandidate &Cand,
39370b57cec5SDimitry Andric                                         SchedCandidate &TryCand) {
39380b57cec5SDimitry Andric   // Initialize the candidate if needed.
39390b57cec5SDimitry Andric   if (!Cand.isValid()) {
39400b57cec5SDimitry Andric     TryCand.Reason = NodeOrder;
3941fe6060f1SDimitry Andric     return true;
39420b57cec5SDimitry Andric   }
39430b57cec5SDimitry Andric 
39440b57cec5SDimitry Andric   // Prioritize instructions that read unbuffered resources by stall cycles.
39450b57cec5SDimitry Andric   if (tryLess(Top.getLatencyStallCycles(TryCand.SU),
39460b57cec5SDimitry Andric               Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
3947fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
39480b57cec5SDimitry Andric 
39490b57cec5SDimitry Andric   // Keep clustered nodes together.
39500b57cec5SDimitry Andric   if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(),
39510b57cec5SDimitry Andric                  Cand.SU == DAG->getNextClusterSucc(),
39520b57cec5SDimitry Andric                  TryCand, Cand, Cluster))
3953fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
39540b57cec5SDimitry Andric 
39550b57cec5SDimitry Andric   // Avoid critical resource consumption and balance the schedule.
39560b57cec5SDimitry Andric   if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
39570b57cec5SDimitry Andric               TryCand, Cand, ResourceReduce))
3958fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
39590b57cec5SDimitry Andric   if (tryGreater(TryCand.ResDelta.DemandedResources,
39600b57cec5SDimitry Andric                  Cand.ResDelta.DemandedResources,
39610b57cec5SDimitry Andric                  TryCand, Cand, ResourceDemand))
3962fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
39630b57cec5SDimitry Andric 
39640b57cec5SDimitry Andric   // Avoid serializing long latency dependence chains.
39650b57cec5SDimitry Andric   if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) {
3966fe6060f1SDimitry Andric     return TryCand.Reason != NoCand;
39670b57cec5SDimitry Andric   }
39680b57cec5SDimitry Andric 
39690b57cec5SDimitry Andric   // Fall through to original instruction order.
3970fe6060f1SDimitry Andric   if (TryCand.SU->NodeNum < Cand.SU->NodeNum) {
39710b57cec5SDimitry Andric     TryCand.Reason = NodeOrder;
3972fe6060f1SDimitry Andric     return true;
3973fe6060f1SDimitry Andric   }
3974fe6060f1SDimitry Andric 
3975fe6060f1SDimitry Andric   return false;
39760b57cec5SDimitry Andric }
39770b57cec5SDimitry Andric 
3978*0fca6ea1SDimitry Andric void PostGenericScheduler::pickNodeFromQueue(SchedBoundary &Zone,
3979*0fca6ea1SDimitry Andric                                              SchedCandidate &Cand) {
3980*0fca6ea1SDimitry Andric   ReadyQueue &Q = Zone.Available;
39810b57cec5SDimitry Andric   for (SUnit *SU : Q) {
39820b57cec5SDimitry Andric     SchedCandidate TryCand(Cand.Policy);
39830b57cec5SDimitry Andric     TryCand.SU = SU;
3984*0fca6ea1SDimitry Andric     TryCand.AtTop = Zone.isTop();
39850b57cec5SDimitry Andric     TryCand.initResourceDelta(DAG, SchedModel);
3986fe6060f1SDimitry Andric     if (tryCandidate(Cand, TryCand)) {
39870b57cec5SDimitry Andric       Cand.setBest(TryCand);
39880b57cec5SDimitry Andric       LLVM_DEBUG(traceCandidate(Cand));
39890b57cec5SDimitry Andric     }
39900b57cec5SDimitry Andric   }
39910b57cec5SDimitry Andric }
39920b57cec5SDimitry Andric 
3993*0fca6ea1SDimitry Andric /// Pick the best candidate node from either the top or bottom queue.
3994*0fca6ea1SDimitry Andric SUnit *PostGenericScheduler::pickNodeBidirectional(bool &IsTopNode) {
3995*0fca6ea1SDimitry Andric   // FIXME: This is similiar to GenericScheduler::pickNodeBidirectional. Factor
3996*0fca6ea1SDimitry Andric   // out common parts.
3997*0fca6ea1SDimitry Andric 
3998*0fca6ea1SDimitry Andric   // Schedule as far as possible in the direction of no choice. This is most
3999*0fca6ea1SDimitry Andric   // efficient, but also provides the best heuristics for CriticalPSets.
4000*0fca6ea1SDimitry Andric   if (SUnit *SU = Bot.pickOnlyChoice()) {
4001*0fca6ea1SDimitry Andric     IsTopNode = false;
4002*0fca6ea1SDimitry Andric     tracePick(Only1, false);
4003*0fca6ea1SDimitry Andric     return SU;
4004*0fca6ea1SDimitry Andric   }
4005*0fca6ea1SDimitry Andric   if (SUnit *SU = Top.pickOnlyChoice()) {
4006*0fca6ea1SDimitry Andric     IsTopNode = true;
4007*0fca6ea1SDimitry Andric     tracePick(Only1, true);
4008*0fca6ea1SDimitry Andric     return SU;
4009*0fca6ea1SDimitry Andric   }
4010*0fca6ea1SDimitry Andric   // Set the bottom-up policy based on the state of the current bottom zone and
4011*0fca6ea1SDimitry Andric   // the instructions outside the zone, including the top zone.
4012*0fca6ea1SDimitry Andric   CandPolicy BotPolicy;
4013*0fca6ea1SDimitry Andric   setPolicy(BotPolicy, /*IsPostRA=*/true, Bot, &Top);
4014*0fca6ea1SDimitry Andric   // Set the top-down policy based on the state of the current top zone and
4015*0fca6ea1SDimitry Andric   // the instructions outside the zone, including the bottom zone.
4016*0fca6ea1SDimitry Andric   CandPolicy TopPolicy;
4017*0fca6ea1SDimitry Andric   setPolicy(TopPolicy, /*IsPostRA=*/true, Top, &Bot);
4018*0fca6ea1SDimitry Andric 
4019*0fca6ea1SDimitry Andric   // See if BotCand is still valid (because we previously scheduled from Top).
4020*0fca6ea1SDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
4021*0fca6ea1SDimitry Andric   if (!BotCand.isValid() || BotCand.SU->isScheduled ||
4022*0fca6ea1SDimitry Andric       BotCand.Policy != BotPolicy) {
4023*0fca6ea1SDimitry Andric     BotCand.reset(CandPolicy());
4024*0fca6ea1SDimitry Andric     pickNodeFromQueue(Bot, BotCand);
4025*0fca6ea1SDimitry Andric     assert(BotCand.Reason != NoCand && "failed to find the first candidate");
4026*0fca6ea1SDimitry Andric   } else {
4027*0fca6ea1SDimitry Andric     LLVM_DEBUG(traceCandidate(BotCand));
4028*0fca6ea1SDimitry Andric #ifndef NDEBUG
4029*0fca6ea1SDimitry Andric     if (VerifyScheduling) {
4030*0fca6ea1SDimitry Andric       SchedCandidate TCand;
4031*0fca6ea1SDimitry Andric       TCand.reset(CandPolicy());
4032*0fca6ea1SDimitry Andric       pickNodeFromQueue(Bot, BotCand);
4033*0fca6ea1SDimitry Andric       assert(TCand.SU == BotCand.SU &&
4034*0fca6ea1SDimitry Andric              "Last pick result should correspond to re-picking right now");
4035*0fca6ea1SDimitry Andric     }
4036*0fca6ea1SDimitry Andric #endif
4037*0fca6ea1SDimitry Andric   }
4038*0fca6ea1SDimitry Andric 
4039*0fca6ea1SDimitry Andric   // Check if the top Q has a better candidate.
4040*0fca6ea1SDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Top:\n");
4041*0fca6ea1SDimitry Andric   if (!TopCand.isValid() || TopCand.SU->isScheduled ||
4042*0fca6ea1SDimitry Andric       TopCand.Policy != TopPolicy) {
4043*0fca6ea1SDimitry Andric     TopCand.reset(CandPolicy());
4044*0fca6ea1SDimitry Andric     pickNodeFromQueue(Top, TopCand);
4045*0fca6ea1SDimitry Andric     assert(TopCand.Reason != NoCand && "failed to find the first candidate");
4046*0fca6ea1SDimitry Andric   } else {
4047*0fca6ea1SDimitry Andric     LLVM_DEBUG(traceCandidate(TopCand));
4048*0fca6ea1SDimitry Andric #ifndef NDEBUG
4049*0fca6ea1SDimitry Andric     if (VerifyScheduling) {
4050*0fca6ea1SDimitry Andric       SchedCandidate TCand;
4051*0fca6ea1SDimitry Andric       TCand.reset(CandPolicy());
4052*0fca6ea1SDimitry Andric       pickNodeFromQueue(Top, TopCand);
4053*0fca6ea1SDimitry Andric       assert(TCand.SU == TopCand.SU &&
4054*0fca6ea1SDimitry Andric              "Last pick result should correspond to re-picking right now");
4055*0fca6ea1SDimitry Andric     }
4056*0fca6ea1SDimitry Andric #endif
4057*0fca6ea1SDimitry Andric   }
4058*0fca6ea1SDimitry Andric 
4059*0fca6ea1SDimitry Andric   // Pick best from BotCand and TopCand.
4060*0fca6ea1SDimitry Andric   assert(BotCand.isValid());
4061*0fca6ea1SDimitry Andric   assert(TopCand.isValid());
4062*0fca6ea1SDimitry Andric   SchedCandidate Cand = BotCand;
4063*0fca6ea1SDimitry Andric   TopCand.Reason = NoCand;
4064*0fca6ea1SDimitry Andric   if (tryCandidate(Cand, TopCand)) {
4065*0fca6ea1SDimitry Andric     Cand.setBest(TopCand);
4066*0fca6ea1SDimitry Andric     LLVM_DEBUG(traceCandidate(Cand));
4067*0fca6ea1SDimitry Andric   }
4068*0fca6ea1SDimitry Andric 
4069*0fca6ea1SDimitry Andric   IsTopNode = Cand.AtTop;
4070*0fca6ea1SDimitry Andric   tracePick(Cand);
4071*0fca6ea1SDimitry Andric   return Cand.SU;
4072*0fca6ea1SDimitry Andric }
4073*0fca6ea1SDimitry Andric 
40740b57cec5SDimitry Andric /// Pick the next node to schedule.
40750b57cec5SDimitry Andric SUnit *PostGenericScheduler::pickNode(bool &IsTopNode) {
40760b57cec5SDimitry Andric   if (DAG->top() == DAG->bottom()) {
4077*0fca6ea1SDimitry Andric     assert(Top.Available.empty() && Top.Pending.empty() &&
4078*0fca6ea1SDimitry Andric            Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
40790b57cec5SDimitry Andric     return nullptr;
40800b57cec5SDimitry Andric   }
40810b57cec5SDimitry Andric   SUnit *SU;
40820b57cec5SDimitry Andric   do {
4083*0fca6ea1SDimitry Andric     if (RegionPolicy.OnlyBottomUp) {
4084*0fca6ea1SDimitry Andric       SU = Bot.pickOnlyChoice();
4085*0fca6ea1SDimitry Andric       if (SU) {
4086*0fca6ea1SDimitry Andric         tracePick(Only1, true);
4087*0fca6ea1SDimitry Andric       } else {
4088*0fca6ea1SDimitry Andric         CandPolicy NoPolicy;
4089*0fca6ea1SDimitry Andric         BotCand.reset(NoPolicy);
4090*0fca6ea1SDimitry Andric         // Set the bottom-up policy based on the state of the current bottom
4091*0fca6ea1SDimitry Andric         // zone and the instructions outside the zone, including the top zone.
4092*0fca6ea1SDimitry Andric         setPolicy(BotCand.Policy, /*IsPostRA=*/true, Bot, nullptr);
4093*0fca6ea1SDimitry Andric         pickNodeFromQueue(Bot, BotCand);
4094*0fca6ea1SDimitry Andric         assert(BotCand.Reason != NoCand && "failed to find a candidate");
4095*0fca6ea1SDimitry Andric         tracePick(BotCand);
4096*0fca6ea1SDimitry Andric         SU = BotCand.SU;
4097*0fca6ea1SDimitry Andric       }
4098*0fca6ea1SDimitry Andric       IsTopNode = false;
4099*0fca6ea1SDimitry Andric     } else if (RegionPolicy.OnlyTopDown) {
41000b57cec5SDimitry Andric       SU = Top.pickOnlyChoice();
41010b57cec5SDimitry Andric       if (SU) {
41020b57cec5SDimitry Andric         tracePick(Only1, true);
41030b57cec5SDimitry Andric       } else {
41040b57cec5SDimitry Andric         CandPolicy NoPolicy;
4105*0fca6ea1SDimitry Andric         TopCand.reset(NoPolicy);
4106*0fca6ea1SDimitry Andric         // Set the top-down policy based on the state of the current top zone
4107*0fca6ea1SDimitry Andric         // and the instructions outside the zone, including the bottom zone.
41080b57cec5SDimitry Andric         setPolicy(TopCand.Policy, /*IsPostRA=*/true, Top, nullptr);
4109*0fca6ea1SDimitry Andric         pickNodeFromQueue(Top, TopCand);
41100b57cec5SDimitry Andric         assert(TopCand.Reason != NoCand && "failed to find a candidate");
41110b57cec5SDimitry Andric         tracePick(TopCand);
41120b57cec5SDimitry Andric         SU = TopCand.SU;
41130b57cec5SDimitry Andric       }
4114*0fca6ea1SDimitry Andric       IsTopNode = true;
4115*0fca6ea1SDimitry Andric     } else {
4116*0fca6ea1SDimitry Andric       SU = pickNodeBidirectional(IsTopNode);
4117*0fca6ea1SDimitry Andric     }
41180b57cec5SDimitry Andric   } while (SU->isScheduled);
41190b57cec5SDimitry Andric 
4120*0fca6ea1SDimitry Andric   if (SU->isTopReady())
41210b57cec5SDimitry Andric     Top.removeReady(SU);
4122*0fca6ea1SDimitry Andric   if (SU->isBottomReady())
4123*0fca6ea1SDimitry Andric     Bot.removeReady(SU);
41240b57cec5SDimitry Andric 
41250b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
41260b57cec5SDimitry Andric                     << *SU->getInstr());
41270b57cec5SDimitry Andric   return SU;
41280b57cec5SDimitry Andric }
41290b57cec5SDimitry Andric 
41300b57cec5SDimitry Andric /// Called after ScheduleDAGMI has scheduled an instruction and updated
41310b57cec5SDimitry Andric /// scheduled/remaining flags in the DAG nodes.
41320b57cec5SDimitry Andric void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
4133*0fca6ea1SDimitry Andric   if (IsTopNode) {
41340b57cec5SDimitry Andric     SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle());
41350b57cec5SDimitry Andric     Top.bumpNode(SU);
4136*0fca6ea1SDimitry Andric   } else {
4137*0fca6ea1SDimitry Andric     SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle());
4138*0fca6ea1SDimitry Andric     Bot.bumpNode(SU);
4139*0fca6ea1SDimitry Andric   }
41400b57cec5SDimitry Andric }
41410b57cec5SDimitry Andric 
41420b57cec5SDimitry Andric ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) {
4143*0fca6ea1SDimitry Andric   ScheduleDAGMI *DAG =
4144*0fca6ea1SDimitry Andric       new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C),
41450b57cec5SDimitry Andric                         /*RemoveKillFlags=*/true);
4146*0fca6ea1SDimitry Andric   const TargetSubtargetInfo &STI = C->MF->getSubtarget();
4147*0fca6ea1SDimitry Andric   // Add MacroFusion mutation if fusions are not empty.
4148*0fca6ea1SDimitry Andric   const auto &MacroFusions = STI.getMacroFusions();
4149*0fca6ea1SDimitry Andric   if (!MacroFusions.empty())
4150*0fca6ea1SDimitry Andric     DAG->addMutation(createMacroFusionDAGMutation(MacroFusions));
4151*0fca6ea1SDimitry Andric   return DAG;
41520b57cec5SDimitry Andric }
41530b57cec5SDimitry Andric 
41540b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
41550b57cec5SDimitry Andric // ILP Scheduler. Currently for experimental analysis of heuristics.
41560b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
41570b57cec5SDimitry Andric 
41580b57cec5SDimitry Andric namespace {
41590b57cec5SDimitry Andric 
41600b57cec5SDimitry Andric /// Order nodes by the ILP metric.
41610b57cec5SDimitry Andric struct ILPOrder {
41620b57cec5SDimitry Andric   const SchedDFSResult *DFSResult = nullptr;
41630b57cec5SDimitry Andric   const BitVector *ScheduledTrees = nullptr;
41640b57cec5SDimitry Andric   bool MaximizeILP;
41650b57cec5SDimitry Andric 
41660b57cec5SDimitry Andric   ILPOrder(bool MaxILP) : MaximizeILP(MaxILP) {}
41670b57cec5SDimitry Andric 
41680b57cec5SDimitry Andric   /// Apply a less-than relation on node priority.
41690b57cec5SDimitry Andric   ///
41700b57cec5SDimitry Andric   /// (Return true if A comes after B in the Q.)
41710b57cec5SDimitry Andric   bool operator()(const SUnit *A, const SUnit *B) const {
41720b57cec5SDimitry Andric     unsigned SchedTreeA = DFSResult->getSubtreeID(A);
41730b57cec5SDimitry Andric     unsigned SchedTreeB = DFSResult->getSubtreeID(B);
41740b57cec5SDimitry Andric     if (SchedTreeA != SchedTreeB) {
41750b57cec5SDimitry Andric       // Unscheduled trees have lower priority.
41760b57cec5SDimitry Andric       if (ScheduledTrees->test(SchedTreeA) != ScheduledTrees->test(SchedTreeB))
41770b57cec5SDimitry Andric         return ScheduledTrees->test(SchedTreeB);
41780b57cec5SDimitry Andric 
41795f757f3fSDimitry Andric       // Trees with shallower connections have lower priority.
41800b57cec5SDimitry Andric       if (DFSResult->getSubtreeLevel(SchedTreeA)
41810b57cec5SDimitry Andric           != DFSResult->getSubtreeLevel(SchedTreeB)) {
41820b57cec5SDimitry Andric         return DFSResult->getSubtreeLevel(SchedTreeA)
41830b57cec5SDimitry Andric           < DFSResult->getSubtreeLevel(SchedTreeB);
41840b57cec5SDimitry Andric       }
41850b57cec5SDimitry Andric     }
41860b57cec5SDimitry Andric     if (MaximizeILP)
41870b57cec5SDimitry Andric       return DFSResult->getILP(A) < DFSResult->getILP(B);
41880b57cec5SDimitry Andric     else
41890b57cec5SDimitry Andric       return DFSResult->getILP(A) > DFSResult->getILP(B);
41900b57cec5SDimitry Andric   }
41910b57cec5SDimitry Andric };
41920b57cec5SDimitry Andric 
41930b57cec5SDimitry Andric /// Schedule based on the ILP metric.
41940b57cec5SDimitry Andric class ILPScheduler : public MachineSchedStrategy {
41950b57cec5SDimitry Andric   ScheduleDAGMILive *DAG = nullptr;
41960b57cec5SDimitry Andric   ILPOrder Cmp;
41970b57cec5SDimitry Andric 
41980b57cec5SDimitry Andric   std::vector<SUnit*> ReadyQ;
41990b57cec5SDimitry Andric 
42000b57cec5SDimitry Andric public:
42010b57cec5SDimitry Andric   ILPScheduler(bool MaximizeILP) : Cmp(MaximizeILP) {}
42020b57cec5SDimitry Andric 
42030b57cec5SDimitry Andric   void initialize(ScheduleDAGMI *dag) override {
42040b57cec5SDimitry Andric     assert(dag->hasVRegLiveness() && "ILPScheduler needs vreg liveness");
42050b57cec5SDimitry Andric     DAG = static_cast<ScheduleDAGMILive*>(dag);
42060b57cec5SDimitry Andric     DAG->computeDFSResult();
42070b57cec5SDimitry Andric     Cmp.DFSResult = DAG->getDFSResult();
42080b57cec5SDimitry Andric     Cmp.ScheduledTrees = &DAG->getScheduledTrees();
42090b57cec5SDimitry Andric     ReadyQ.clear();
42100b57cec5SDimitry Andric   }
42110b57cec5SDimitry Andric 
42120b57cec5SDimitry Andric   void registerRoots() override {
42130b57cec5SDimitry Andric     // Restore the heap in ReadyQ with the updated DFS results.
42140b57cec5SDimitry Andric     std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
42150b57cec5SDimitry Andric   }
42160b57cec5SDimitry Andric 
42170b57cec5SDimitry Andric   /// Implement MachineSchedStrategy interface.
42180b57cec5SDimitry Andric   /// -----------------------------------------
42190b57cec5SDimitry Andric 
42200b57cec5SDimitry Andric   /// Callback to select the highest priority node from the ready Q.
42210b57cec5SDimitry Andric   SUnit *pickNode(bool &IsTopNode) override {
42220b57cec5SDimitry Andric     if (ReadyQ.empty()) return nullptr;
42230b57cec5SDimitry Andric     std::pop_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
42240b57cec5SDimitry Andric     SUnit *SU = ReadyQ.back();
42250b57cec5SDimitry Andric     ReadyQ.pop_back();
42260b57cec5SDimitry Andric     IsTopNode = false;
42270b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Pick node "
42280b57cec5SDimitry Andric                       << "SU(" << SU->NodeNum << ") "
42290b57cec5SDimitry Andric                       << " ILP: " << DAG->getDFSResult()->getILP(SU)
42300b57cec5SDimitry Andric                       << " Tree: " << DAG->getDFSResult()->getSubtreeID(SU)
42310b57cec5SDimitry Andric                       << " @"
42320b57cec5SDimitry Andric                       << DAG->getDFSResult()->getSubtreeLevel(
42330b57cec5SDimitry Andric                              DAG->getDFSResult()->getSubtreeID(SU))
42340b57cec5SDimitry Andric                       << '\n'
42350b57cec5SDimitry Andric                       << "Scheduling " << *SU->getInstr());
42360b57cec5SDimitry Andric     return SU;
42370b57cec5SDimitry Andric   }
42380b57cec5SDimitry Andric 
42390b57cec5SDimitry Andric   /// Scheduler callback to notify that a new subtree is scheduled.
42400b57cec5SDimitry Andric   void scheduleTree(unsigned SubtreeID) override {
42410b57cec5SDimitry Andric     std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
42420b57cec5SDimitry Andric   }
42430b57cec5SDimitry Andric 
42440b57cec5SDimitry Andric   /// Callback after a node is scheduled. Mark a newly scheduled tree, notify
42450b57cec5SDimitry Andric   /// DFSResults, and resort the priority Q.
42460b57cec5SDimitry Andric   void schedNode(SUnit *SU, bool IsTopNode) override {
42470b57cec5SDimitry Andric     assert(!IsTopNode && "SchedDFSResult needs bottom-up");
42480b57cec5SDimitry Andric   }
42490b57cec5SDimitry Andric 
42500b57cec5SDimitry Andric   void releaseTopNode(SUnit *) override { /*only called for top roots*/ }
42510b57cec5SDimitry Andric 
42520b57cec5SDimitry Andric   void releaseBottomNode(SUnit *SU) override {
42530b57cec5SDimitry Andric     ReadyQ.push_back(SU);
42540b57cec5SDimitry Andric     std::push_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
42550b57cec5SDimitry Andric   }
42560b57cec5SDimitry Andric };
42570b57cec5SDimitry Andric 
42580b57cec5SDimitry Andric } // end anonymous namespace
42590b57cec5SDimitry Andric 
42600b57cec5SDimitry Andric static ScheduleDAGInstrs *createILPMaxScheduler(MachineSchedContext *C) {
42618bcb0991SDimitry Andric   return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(true));
42620b57cec5SDimitry Andric }
42630b57cec5SDimitry Andric static ScheduleDAGInstrs *createILPMinScheduler(MachineSchedContext *C) {
42648bcb0991SDimitry Andric   return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(false));
42650b57cec5SDimitry Andric }
42660b57cec5SDimitry Andric 
42670b57cec5SDimitry Andric static MachineSchedRegistry ILPMaxRegistry(
42680b57cec5SDimitry Andric   "ilpmax", "Schedule bottom-up for max ILP", createILPMaxScheduler);
42690b57cec5SDimitry Andric static MachineSchedRegistry ILPMinRegistry(
42700b57cec5SDimitry Andric   "ilpmin", "Schedule bottom-up for min ILP", createILPMinScheduler);
42710b57cec5SDimitry Andric 
42720b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
42730b57cec5SDimitry Andric // Machine Instruction Shuffler for Correctness Testing
42740b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
42750b57cec5SDimitry Andric 
42760b57cec5SDimitry Andric #ifndef NDEBUG
42770b57cec5SDimitry Andric namespace {
42780b57cec5SDimitry Andric 
42790b57cec5SDimitry Andric /// Apply a less-than relation on the node order, which corresponds to the
42800b57cec5SDimitry Andric /// instruction order prior to scheduling. IsReverse implements greater-than.
42810b57cec5SDimitry Andric template<bool IsReverse>
42820b57cec5SDimitry Andric struct SUnitOrder {
42830b57cec5SDimitry Andric   bool operator()(SUnit *A, SUnit *B) const {
42840b57cec5SDimitry Andric     if (IsReverse)
42850b57cec5SDimitry Andric       return A->NodeNum > B->NodeNum;
42860b57cec5SDimitry Andric     else
42870b57cec5SDimitry Andric       return A->NodeNum < B->NodeNum;
42880b57cec5SDimitry Andric   }
42890b57cec5SDimitry Andric };
42900b57cec5SDimitry Andric 
42910b57cec5SDimitry Andric /// Reorder instructions as much as possible.
42920b57cec5SDimitry Andric class InstructionShuffler : public MachineSchedStrategy {
42930b57cec5SDimitry Andric   bool IsAlternating;
42940b57cec5SDimitry Andric   bool IsTopDown;
42950b57cec5SDimitry Andric 
42960b57cec5SDimitry Andric   // Using a less-than relation (SUnitOrder<false>) for the TopQ priority
42970b57cec5SDimitry Andric   // gives nodes with a higher number higher priority causing the latest
42980b57cec5SDimitry Andric   // instructions to be scheduled first.
42990b57cec5SDimitry Andric   PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<false>>
43000b57cec5SDimitry Andric     TopQ;
43010b57cec5SDimitry Andric 
43020b57cec5SDimitry Andric   // When scheduling bottom-up, use greater-than as the queue priority.
43030b57cec5SDimitry Andric   PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<true>>
43040b57cec5SDimitry Andric     BottomQ;
43050b57cec5SDimitry Andric 
43060b57cec5SDimitry Andric public:
43070b57cec5SDimitry Andric   InstructionShuffler(bool alternate, bool topdown)
43080b57cec5SDimitry Andric     : IsAlternating(alternate), IsTopDown(topdown) {}
43090b57cec5SDimitry Andric 
43100b57cec5SDimitry Andric   void initialize(ScheduleDAGMI*) override {
43110b57cec5SDimitry Andric     TopQ.clear();
43120b57cec5SDimitry Andric     BottomQ.clear();
43130b57cec5SDimitry Andric   }
43140b57cec5SDimitry Andric 
43150b57cec5SDimitry Andric   /// Implement MachineSchedStrategy interface.
43160b57cec5SDimitry Andric   /// -----------------------------------------
43170b57cec5SDimitry Andric 
43180b57cec5SDimitry Andric   SUnit *pickNode(bool &IsTopNode) override {
43190b57cec5SDimitry Andric     SUnit *SU;
43200b57cec5SDimitry Andric     if (IsTopDown) {
43210b57cec5SDimitry Andric       do {
43220b57cec5SDimitry Andric         if (TopQ.empty()) return nullptr;
43230b57cec5SDimitry Andric         SU = TopQ.top();
43240b57cec5SDimitry Andric         TopQ.pop();
43250b57cec5SDimitry Andric       } while (SU->isScheduled);
43260b57cec5SDimitry Andric       IsTopNode = true;
43270b57cec5SDimitry Andric     } else {
43280b57cec5SDimitry Andric       do {
43290b57cec5SDimitry Andric         if (BottomQ.empty()) return nullptr;
43300b57cec5SDimitry Andric         SU = BottomQ.top();
43310b57cec5SDimitry Andric         BottomQ.pop();
43320b57cec5SDimitry Andric       } while (SU->isScheduled);
43330b57cec5SDimitry Andric       IsTopNode = false;
43340b57cec5SDimitry Andric     }
43350b57cec5SDimitry Andric     if (IsAlternating)
43360b57cec5SDimitry Andric       IsTopDown = !IsTopDown;
43370b57cec5SDimitry Andric     return SU;
43380b57cec5SDimitry Andric   }
43390b57cec5SDimitry Andric 
43400b57cec5SDimitry Andric   void schedNode(SUnit *SU, bool IsTopNode) override {}
43410b57cec5SDimitry Andric 
43420b57cec5SDimitry Andric   void releaseTopNode(SUnit *SU) override {
43430b57cec5SDimitry Andric     TopQ.push(SU);
43440b57cec5SDimitry Andric   }
43450b57cec5SDimitry Andric   void releaseBottomNode(SUnit *SU) override {
43460b57cec5SDimitry Andric     BottomQ.push(SU);
43470b57cec5SDimitry Andric   }
43480b57cec5SDimitry Andric };
43490b57cec5SDimitry Andric 
43500b57cec5SDimitry Andric } // end anonymous namespace
43510b57cec5SDimitry Andric 
43520b57cec5SDimitry Andric static ScheduleDAGInstrs *createInstructionShuffler(MachineSchedContext *C) {
43530b57cec5SDimitry Andric   bool Alternate = !ForceTopDown && !ForceBottomUp;
43540b57cec5SDimitry Andric   bool TopDown = !ForceBottomUp;
43550b57cec5SDimitry Andric   assert((TopDown || !ForceTopDown) &&
43560b57cec5SDimitry Andric          "-misched-topdown incompatible with -misched-bottomup");
43570b57cec5SDimitry Andric   return new ScheduleDAGMILive(
43588bcb0991SDimitry Andric       C, std::make_unique<InstructionShuffler>(Alternate, TopDown));
43590b57cec5SDimitry Andric }
43600b57cec5SDimitry Andric 
43610b57cec5SDimitry Andric static MachineSchedRegistry ShufflerRegistry(
43620b57cec5SDimitry Andric   "shuffle", "Shuffle machine instructions alternating directions",
43630b57cec5SDimitry Andric   createInstructionShuffler);
43640b57cec5SDimitry Andric #endif // !NDEBUG
43650b57cec5SDimitry Andric 
43660b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
43670b57cec5SDimitry Andric // GraphWriter support for ScheduleDAGMILive.
43680b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
43690b57cec5SDimitry Andric 
43700b57cec5SDimitry Andric #ifndef NDEBUG
43710b57cec5SDimitry Andric namespace llvm {
43720b57cec5SDimitry Andric 
43730b57cec5SDimitry Andric template<> struct GraphTraits<
43740b57cec5SDimitry Andric   ScheduleDAGMI*> : public GraphTraits<ScheduleDAG*> {};
43750b57cec5SDimitry Andric 
43760b57cec5SDimitry Andric template<>
43770b57cec5SDimitry Andric struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits {
43780b57cec5SDimitry Andric   DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
43790b57cec5SDimitry Andric 
43800b57cec5SDimitry Andric   static std::string getGraphName(const ScheduleDAG *G) {
43815ffd83dbSDimitry Andric     return std::string(G->MF.getName());
43820b57cec5SDimitry Andric   }
43830b57cec5SDimitry Andric 
43840b57cec5SDimitry Andric   static bool renderGraphFromBottomUp() {
43850b57cec5SDimitry Andric     return true;
43860b57cec5SDimitry Andric   }
43870b57cec5SDimitry Andric 
4388e8d8bef9SDimitry Andric   static bool isNodeHidden(const SUnit *Node, const ScheduleDAG *G) {
43890b57cec5SDimitry Andric     if (ViewMISchedCutoff == 0)
43900b57cec5SDimitry Andric       return false;
43910b57cec5SDimitry Andric     return (Node->Preds.size() > ViewMISchedCutoff
43920b57cec5SDimitry Andric          || Node->Succs.size() > ViewMISchedCutoff);
43930b57cec5SDimitry Andric   }
43940b57cec5SDimitry Andric 
43950b57cec5SDimitry Andric   /// If you want to override the dot attributes printed for a particular
43960b57cec5SDimitry Andric   /// edge, override this method.
43970b57cec5SDimitry Andric   static std::string getEdgeAttributes(const SUnit *Node,
43980b57cec5SDimitry Andric                                        SUnitIterator EI,
43990b57cec5SDimitry Andric                                        const ScheduleDAG *Graph) {
44000b57cec5SDimitry Andric     if (EI.isArtificialDep())
44010b57cec5SDimitry Andric       return "color=cyan,style=dashed";
44020b57cec5SDimitry Andric     if (EI.isCtrlDep())
44030b57cec5SDimitry Andric       return "color=blue,style=dashed";
44040b57cec5SDimitry Andric     return "";
44050b57cec5SDimitry Andric   }
44060b57cec5SDimitry Andric 
44070b57cec5SDimitry Andric   static std::string getNodeLabel(const SUnit *SU, const ScheduleDAG *G) {
44080b57cec5SDimitry Andric     std::string Str;
44090b57cec5SDimitry Andric     raw_string_ostream SS(Str);
44100b57cec5SDimitry Andric     const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
44110b57cec5SDimitry Andric     const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
44120b57cec5SDimitry Andric       static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
44130b57cec5SDimitry Andric     SS << "SU:" << SU->NodeNum;
44140b57cec5SDimitry Andric     if (DFS)
44150b57cec5SDimitry Andric       SS << " I:" << DFS->getNumInstrs(SU);
4416*0fca6ea1SDimitry Andric     return Str;
44170b57cec5SDimitry Andric   }
44180b57cec5SDimitry Andric 
44190b57cec5SDimitry Andric   static std::string getNodeDescription(const SUnit *SU, const ScheduleDAG *G) {
44200b57cec5SDimitry Andric     return G->getGraphNodeLabel(SU);
44210b57cec5SDimitry Andric   }
44220b57cec5SDimitry Andric 
44230b57cec5SDimitry Andric   static std::string getNodeAttributes(const SUnit *N, const ScheduleDAG *G) {
44240b57cec5SDimitry Andric     std::string Str("shape=Mrecord");
44250b57cec5SDimitry Andric     const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
44260b57cec5SDimitry Andric     const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
44270b57cec5SDimitry Andric       static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
44280b57cec5SDimitry Andric     if (DFS) {
44290b57cec5SDimitry Andric       Str += ",style=filled,fillcolor=\"#";
44300b57cec5SDimitry Andric       Str += DOT::getColorString(DFS->getSubtreeID(N));
44310b57cec5SDimitry Andric       Str += '"';
44320b57cec5SDimitry Andric     }
44330b57cec5SDimitry Andric     return Str;
44340b57cec5SDimitry Andric   }
44350b57cec5SDimitry Andric };
44360b57cec5SDimitry Andric 
44370b57cec5SDimitry Andric } // end namespace llvm
44380b57cec5SDimitry Andric #endif // NDEBUG
44390b57cec5SDimitry Andric 
44400b57cec5SDimitry Andric /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
44410b57cec5SDimitry Andric /// rendered using 'dot'.
44420b57cec5SDimitry Andric void ScheduleDAGMI::viewGraph(const Twine &Name, const Twine &Title) {
44430b57cec5SDimitry Andric #ifndef NDEBUG
44440b57cec5SDimitry Andric   ViewGraph(this, Name, false, Title);
44450b57cec5SDimitry Andric #else
44460b57cec5SDimitry Andric   errs() << "ScheduleDAGMI::viewGraph is only available in debug builds on "
44470b57cec5SDimitry Andric          << "systems with Graphviz or gv!\n";
44480b57cec5SDimitry Andric #endif  // NDEBUG
44490b57cec5SDimitry Andric }
44500b57cec5SDimitry Andric 
44510b57cec5SDimitry Andric /// Out-of-line implementation with no arguments is handy for gdb.
44520b57cec5SDimitry Andric void ScheduleDAGMI::viewGraph() {
44530b57cec5SDimitry Andric   viewGraph(getDAGName(), "Scheduling-Units Graph for " + getDAGName());
44540b57cec5SDimitry Andric }
445506c3fb27SDimitry Andric 
445606c3fb27SDimitry Andric /// Sort predicate for the intervals stored in an instance of
445706c3fb27SDimitry Andric /// ResourceSegments. Intervals are always disjoint (no intersection
445806c3fb27SDimitry Andric /// for any pairs of intervals), therefore we can sort the totality of
445906c3fb27SDimitry Andric /// the intervals by looking only at the left boundary.
446006c3fb27SDimitry Andric static bool sortIntervals(const ResourceSegments::IntervalTy &A,
446106c3fb27SDimitry Andric                           const ResourceSegments::IntervalTy &B) {
446206c3fb27SDimitry Andric   return A.first < B.first;
446306c3fb27SDimitry Andric }
446406c3fb27SDimitry Andric 
446506c3fb27SDimitry Andric unsigned ResourceSegments::getFirstAvailableAt(
44667a6dacacSDimitry Andric     unsigned CurrCycle, unsigned AcquireAtCycle, unsigned ReleaseAtCycle,
446706c3fb27SDimitry Andric     std::function<ResourceSegments::IntervalTy(unsigned, unsigned, unsigned)>
446806c3fb27SDimitry Andric         IntervalBuilder) const {
446906c3fb27SDimitry Andric   assert(std::is_sorted(std::begin(_Intervals), std::end(_Intervals),
447006c3fb27SDimitry Andric                         sortIntervals) &&
447106c3fb27SDimitry Andric          "Cannot execute on an un-sorted set of intervals.");
4472*0fca6ea1SDimitry Andric 
4473*0fca6ea1SDimitry Andric   // Zero resource usage is allowed by TargetSchedule.td but we do not construct
4474*0fca6ea1SDimitry Andric   // a ResourceSegment interval for that situation.
4475*0fca6ea1SDimitry Andric   if (AcquireAtCycle == ReleaseAtCycle)
4476*0fca6ea1SDimitry Andric     return CurrCycle;
4477*0fca6ea1SDimitry Andric 
447806c3fb27SDimitry Andric   unsigned RetCycle = CurrCycle;
447906c3fb27SDimitry Andric   ResourceSegments::IntervalTy NewInterval =
44807a6dacacSDimitry Andric       IntervalBuilder(RetCycle, AcquireAtCycle, ReleaseAtCycle);
448106c3fb27SDimitry Andric   for (auto &Interval : _Intervals) {
448206c3fb27SDimitry Andric     if (!intersects(NewInterval, Interval))
448306c3fb27SDimitry Andric       continue;
448406c3fb27SDimitry Andric 
448506c3fb27SDimitry Andric     // Move the interval right next to the top of the one it
448606c3fb27SDimitry Andric     // intersects.
448706c3fb27SDimitry Andric     assert(Interval.second > NewInterval.first &&
448806c3fb27SDimitry Andric            "Invalid intervals configuration.");
448906c3fb27SDimitry Andric     RetCycle += (unsigned)Interval.second - (unsigned)NewInterval.first;
44907a6dacacSDimitry Andric     NewInterval = IntervalBuilder(RetCycle, AcquireAtCycle, ReleaseAtCycle);
449106c3fb27SDimitry Andric   }
449206c3fb27SDimitry Andric   return RetCycle;
449306c3fb27SDimitry Andric }
449406c3fb27SDimitry Andric 
449506c3fb27SDimitry Andric void ResourceSegments::add(ResourceSegments::IntervalTy A,
449606c3fb27SDimitry Andric                            const unsigned CutOff) {
4497*0fca6ea1SDimitry Andric   assert(A.first <= A.second && "Cannot add negative resource usage");
449806c3fb27SDimitry Andric   assert(CutOff > 0 && "0-size interval history has no use.");
4499*0fca6ea1SDimitry Andric   // Zero resource usage is allowed by TargetSchedule.td, in the case that the
4500*0fca6ea1SDimitry Andric   // instruction needed the resource to be available but does not use it.
4501*0fca6ea1SDimitry Andric   // However, ResourceSegment represents an interval that is closed on the left
4502*0fca6ea1SDimitry Andric   // and open on the right. It is impossible to represent an empty interval when
4503*0fca6ea1SDimitry Andric   // the left is closed. Do not add it to Intervals.
4504*0fca6ea1SDimitry Andric   if (A.first == A.second)
4505*0fca6ea1SDimitry Andric     return;
4506*0fca6ea1SDimitry Andric 
450706c3fb27SDimitry Andric   assert(all_of(_Intervals,
450806c3fb27SDimitry Andric                 [&A](const ResourceSegments::IntervalTy &Interval) -> bool {
450906c3fb27SDimitry Andric                   return !intersects(A, Interval);
451006c3fb27SDimitry Andric                 }) &&
451106c3fb27SDimitry Andric          "A resource is being overwritten");
451206c3fb27SDimitry Andric   _Intervals.push_back(A);
451306c3fb27SDimitry Andric 
451406c3fb27SDimitry Andric   sortAndMerge();
451506c3fb27SDimitry Andric 
451606c3fb27SDimitry Andric   // Do not keep the full history of the intervals, just the
451706c3fb27SDimitry Andric   // latest #CutOff.
451806c3fb27SDimitry Andric   while (_Intervals.size() > CutOff)
451906c3fb27SDimitry Andric     _Intervals.pop_front();
452006c3fb27SDimitry Andric }
452106c3fb27SDimitry Andric 
452206c3fb27SDimitry Andric bool ResourceSegments::intersects(ResourceSegments::IntervalTy A,
452306c3fb27SDimitry Andric                                   ResourceSegments::IntervalTy B) {
452406c3fb27SDimitry Andric   assert(A.first <= A.second && "Invalid interval");
452506c3fb27SDimitry Andric   assert(B.first <= B.second && "Invalid interval");
452606c3fb27SDimitry Andric 
452706c3fb27SDimitry Andric   // Share one boundary.
452806c3fb27SDimitry Andric   if ((A.first == B.first) || (A.second == B.second))
452906c3fb27SDimitry Andric     return true;
453006c3fb27SDimitry Andric 
453106c3fb27SDimitry Andric   // full intersersect: [    ***     )  B
453206c3fb27SDimitry Andric   //                        [***)       A
453306c3fb27SDimitry Andric   if ((A.first > B.first) && (A.second < B.second))
453406c3fb27SDimitry Andric     return true;
453506c3fb27SDimitry Andric 
453606c3fb27SDimitry Andric   // right intersect: [     ***)        B
453706c3fb27SDimitry Andric   //                       [***      )  A
453806c3fb27SDimitry Andric   if ((A.first > B.first) && (A.first < B.second) && (A.second > B.second))
453906c3fb27SDimitry Andric     return true;
454006c3fb27SDimitry Andric 
454106c3fb27SDimitry Andric   // left intersect:      [***      )  B
454206c3fb27SDimitry Andric   //                 [     ***)        A
454306c3fb27SDimitry Andric   if ((A.first < B.first) && (B.first < A.second) && (B.second > B.first))
454406c3fb27SDimitry Andric     return true;
454506c3fb27SDimitry Andric 
454606c3fb27SDimitry Andric   return false;
454706c3fb27SDimitry Andric }
454806c3fb27SDimitry Andric 
454906c3fb27SDimitry Andric void ResourceSegments::sortAndMerge() {
455006c3fb27SDimitry Andric   if (_Intervals.size() <= 1)
455106c3fb27SDimitry Andric     return;
455206c3fb27SDimitry Andric 
455306c3fb27SDimitry Andric   // First sort the collection.
455406c3fb27SDimitry Andric   _Intervals.sort(sortIntervals);
455506c3fb27SDimitry Andric 
455606c3fb27SDimitry Andric   // can use next because I have at least 2 elements in the list
455706c3fb27SDimitry Andric   auto next = std::next(std::begin(_Intervals));
455806c3fb27SDimitry Andric   auto E = std::end(_Intervals);
455906c3fb27SDimitry Andric   for (; next != E; ++next) {
456006c3fb27SDimitry Andric     if (std::prev(next)->second >= next->first) {
456106c3fb27SDimitry Andric       next->first = std::prev(next)->first;
456206c3fb27SDimitry Andric       _Intervals.erase(std::prev(next));
456306c3fb27SDimitry Andric       continue;
456406c3fb27SDimitry Andric     }
456506c3fb27SDimitry Andric   }
456606c3fb27SDimitry Andric }
4567